IOWin: Use anonymous namespaces where applicable
Several functions (and one variable) were being given external linkage. Instead, relocate them all to anonymous namespaces to make them internally linked.
This commit is contained in:
parent
307d5d5482
commit
8753321841
|
@ -55,12 +55,14 @@ DYN_FUNC_DECLARE(BluetoothEnumerateInstalledServices);
|
|||
|
||||
#undef DYN_FUNC_DECLARE
|
||||
|
||||
static HINSTANCE s_hid_lib = nullptr;
|
||||
static HINSTANCE s_bthprops_lib = nullptr;
|
||||
namespace
|
||||
{
|
||||
HINSTANCE s_hid_lib = nullptr;
|
||||
HINSTANCE s_bthprops_lib = nullptr;
|
||||
|
||||
static bool s_loaded_ok = false;
|
||||
bool s_loaded_ok = false;
|
||||
|
||||
std::unordered_map<BTH_ADDR, std::time_t> g_connect_times;
|
||||
std::unordered_map<BTH_ADDR, std::time_t> s_connect_times;
|
||||
|
||||
#define DYN_FUNC_UNLOAD(func) p##func = nullptr;
|
||||
|
||||
|
@ -161,7 +163,7 @@ bool load_bthprops()
|
|||
#undef DYN_FUNC_LOAD
|
||||
#undef DYN_FUNC_UNLOAD
|
||||
|
||||
inline void init_lib()
|
||||
void init_lib()
|
||||
{
|
||||
static bool initialized = false;
|
||||
|
||||
|
@ -181,6 +183,7 @@ inline void init_lib()
|
|||
s_loaded_ok = true;
|
||||
}
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
namespace WiimoteReal
|
||||
{
|
||||
|
@ -195,44 +198,138 @@ bool AttachWiimote(HANDLE hRadio, const BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_
|
|||
void RemoveWiimote(BLUETOOTH_DEVICE_INFO_STRUCT&);
|
||||
bool ForgetWiimote(BLUETOOTH_DEVICE_INFO_STRUCT&);
|
||||
|
||||
WiimoteScannerWindows::WiimoteScannerWindows()
|
||||
namespace
|
||||
{
|
||||
init_lib();
|
||||
std::wstring GetDeviceProperty(const HDEVINFO& device_info, const PSP_DEVINFO_DATA device_data,
|
||||
const DEVPROPKEY* requested_property)
|
||||
{
|
||||
DWORD required_size = 0;
|
||||
DEVPROPTYPE device_property_type;
|
||||
|
||||
SetupDiGetDeviceProperty(device_info, device_data, requested_property, &device_property_type,
|
||||
nullptr, 0, &required_size, 0);
|
||||
|
||||
std::vector<BYTE> unicode_buffer(required_size, 0);
|
||||
|
||||
BOOL result =
|
||||
SetupDiGetDeviceProperty(device_info, device_data, requested_property, &device_property_type,
|
||||
unicode_buffer.data(), required_size, nullptr, 0);
|
||||
if (!result)
|
||||
{
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
return std::wstring((PWCHAR)unicode_buffer.data());
|
||||
}
|
||||
|
||||
WiimoteScannerWindows::~WiimoteScannerWindows()
|
||||
int IOWritePerSetOutputReport(HANDLE& dev_handle, const u8* buf, size_t len, DWORD* written)
|
||||
{
|
||||
// TODO: what do we want here?
|
||||
#if 0
|
||||
ProcessWiimotes(false, [](HANDLE, BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
|
||||
{
|
||||
RemoveWiimote(btdi);
|
||||
});
|
||||
#endif
|
||||
BOOLEAN result = pHidD_SetOutputReport(dev_handle, const_cast<u8*>(buf) + 1, (ULONG)(len - 1));
|
||||
if (!result)
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_SEM_TIMEOUT)
|
||||
{
|
||||
NOTICE_LOG(WIIMOTE, "IOWrite[WWM_SET_OUTPUT_REPORT]: Unable to send data to the Wiimote");
|
||||
}
|
||||
else if (err != ERROR_GEN_FAILURE)
|
||||
{
|
||||
// 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[WWM_SET_OUTPUT_REPORT]: Error: %08x", err);
|
||||
}
|
||||
}
|
||||
|
||||
if (written)
|
||||
{
|
||||
*written = (result ? (DWORD)len : 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void WiimoteScannerWindows::Update()
|
||||
int IOWritePerWriteFile(HANDLE& dev_handle, OVERLAPPED& hid_overlap_write,
|
||||
WinWriteMethod& write_method, const u8* buf, size_t len, DWORD* written)
|
||||
{
|
||||
if (!s_loaded_ok)
|
||||
return;
|
||||
DWORD bytes_written;
|
||||
LPCVOID write_buffer = buf + 1;
|
||||
DWORD bytes_to_write = (DWORD)(len - 1);
|
||||
|
||||
bool forgot_some = false;
|
||||
u8 resized_buffer[MAX_PAYLOAD];
|
||||
|
||||
ProcessWiimotes(false, [&](HANDLE, BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT& btdi) {
|
||||
forgot_some |= ForgetWiimote(btdi);
|
||||
});
|
||||
// Resize the buffer, if the underlying HID Class driver needs the buffer to be the size of
|
||||
// HidCaps.OuputReportSize
|
||||
// In case of Wiimote HidCaps.OuputReportSize is 22 Byte.
|
||||
// This is currently needed by the Toshiba Bluetooth Stack.
|
||||
if ((write_method == WWM_WRITE_FILE_LARGEST_REPORT_SIZE) && (MAX_PAYLOAD > len))
|
||||
{
|
||||
std::copy(buf, buf + len, resized_buffer);
|
||||
std::fill(resized_buffer + len, resized_buffer + MAX_PAYLOAD, 0);
|
||||
write_buffer = resized_buffer + 1;
|
||||
bytes_to_write = MAX_PAYLOAD - 1;
|
||||
}
|
||||
|
||||
// Some hacks that allows disconnects to be detected before connections are handled
|
||||
// workaround for Wiimote 1 moving to slot 2 on temporary disconnect
|
||||
if (forgot_some)
|
||||
Common::SleepCurrentThread(100);
|
||||
ResetEvent(hid_overlap_write.hEvent);
|
||||
BOOLEAN result =
|
||||
WriteFile(dev_handle, write_buffer, bytes_to_write, &bytes_written, &hid_overlap_write);
|
||||
if (!result)
|
||||
{
|
||||
const DWORD error = GetLastError();
|
||||
|
||||
switch (error)
|
||||
{
|
||||
case ERROR_INVALID_USER_BUFFER:
|
||||
INFO_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: Falling back to SetOutputReport");
|
||||
write_method = WWM_SET_OUTPUT_REPORT;
|
||||
return IOWritePerSetOutputReport(dev_handle, buf, len, written);
|
||||
case ERROR_IO_PENDING:
|
||||
// Pending is no error!
|
||||
break;
|
||||
default:
|
||||
WARN_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: Error on WriteFile: %08x", error);
|
||||
CancelIo(dev_handle);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (written)
|
||||
{
|
||||
*written = 0;
|
||||
}
|
||||
|
||||
// Wait for completion
|
||||
DWORD wait_result = WaitForSingleObject(hid_overlap_write.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
|
||||
|
||||
if (WAIT_TIMEOUT == wait_result)
|
||||
{
|
||||
WARN_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: A timeout occurred on writing to Wiimote.");
|
||||
CancelIo(dev_handle);
|
||||
return 1;
|
||||
}
|
||||
else if (WAIT_FAILED == wait_result)
|
||||
{
|
||||
WARN_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: A wait error occurred on writing to Wiimote.");
|
||||
CancelIo(dev_handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (written)
|
||||
{
|
||||
if (!GetOverlappedResult(dev_handle, &hid_overlap_write, written, TRUE))
|
||||
{
|
||||
*written = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Moves up one node in the device tree and returns its device info data along with an info set only
|
||||
// including that device for further processing
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/hardware/ff549417(v=vs.85).aspx
|
||||
static bool GetParentDevice(const DEVINST& child_device_instance, HDEVINFO* parent_device_info,
|
||||
PSP_DEVINFO_DATA parent_device_data)
|
||||
bool GetParentDevice(const DEVINST& child_device_instance, HDEVINFO* parent_device_info,
|
||||
PSP_DEVINFO_DATA parent_device_data)
|
||||
{
|
||||
ULONG status;
|
||||
ULONG problem_number;
|
||||
|
@ -279,28 +376,6 @@ static bool GetParentDevice(const DEVINST& child_device_instance, HDEVINFO* pare
|
|||
return true;
|
||||
}
|
||||
|
||||
std::wstring GetDeviceProperty(const HDEVINFO& device_info, const PSP_DEVINFO_DATA device_data,
|
||||
const DEVPROPKEY* requested_property)
|
||||
{
|
||||
DWORD required_size = 0;
|
||||
DEVPROPTYPE device_property_type;
|
||||
|
||||
SetupDiGetDeviceProperty(device_info, device_data, requested_property, &device_property_type,
|
||||
nullptr, 0, &required_size, 0);
|
||||
|
||||
std::vector<BYTE> unicode_buffer(required_size, 0);
|
||||
|
||||
BOOL result =
|
||||
SetupDiGetDeviceProperty(device_info, device_data, requested_property, &device_property_type,
|
||||
unicode_buffer.data(), required_size, nullptr, 0);
|
||||
if (!result)
|
||||
{
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
return std::wstring((PWCHAR)unicode_buffer.data());
|
||||
}
|
||||
|
||||
// The enumerated device nodes/instances are "empty" PDO's that act as interfaces for the HID Class
|
||||
// Driver.
|
||||
// Since those PDO's normaly don't have a FDO and therefore no driver loaded, we need to move one
|
||||
|
@ -308,7 +383,7 @@ std::wstring GetDeviceProperty(const HDEVINFO& device_info, const PSP_DEVINFO_DA
|
|||
// Then check the provider of the device driver, which will be "Microsoft" in case of the default
|
||||
// HID Class Driver
|
||||
// or "TOSHIBA" in case of the Toshiba Bluetooth Stack, because it provides its own Class Driver.
|
||||
static bool CheckForToshibaStack(const DEVINST& hid_interface_device_instance)
|
||||
bool CheckForToshibaStack(const DEVINST& hid_interface_device_instance)
|
||||
{
|
||||
HDEVINFO parent_device_info = nullptr;
|
||||
SP_DEVINFO_DATA parent_device_data = {};
|
||||
|
@ -329,7 +404,7 @@ static bool CheckForToshibaStack(const DEVINST& hid_interface_device_instance)
|
|||
return false;
|
||||
}
|
||||
|
||||
static WinWriteMethod GetInitialWriteMethod(bool IsUsingToshibaStack)
|
||||
WinWriteMethod GetInitialWriteMethod(bool IsUsingToshibaStack)
|
||||
{
|
||||
// Currently Toshiba Bluetooth Stack needs the Output buffer to be the size of the largest output
|
||||
// report
|
||||
|
@ -337,7 +412,7 @@ static WinWriteMethod GetInitialWriteMethod(bool IsUsingToshibaStack)
|
|||
WWM_WRITE_FILE_ACTUAL_REPORT_SIZE);
|
||||
}
|
||||
|
||||
static int WriteToHandle(HANDLE& dev_handle, WinWriteMethod& method, const u8* buf, size_t size)
|
||||
int WriteToHandle(HANDLE& dev_handle, WinWriteMethod& method, const u8* buf, size_t size)
|
||||
{
|
||||
OVERLAPPED hid_overlap_write = OVERLAPPED();
|
||||
hid_overlap_write.hEvent = CreateEvent(nullptr, true, false, nullptr);
|
||||
|
@ -350,7 +425,7 @@ static int WriteToHandle(HANDLE& dev_handle, WinWriteMethod& method, const u8* b
|
|||
return written;
|
||||
}
|
||||
|
||||
static int ReadFromHandle(HANDLE& dev_handle, u8* buf)
|
||||
int ReadFromHandle(HANDLE& dev_handle, u8* buf)
|
||||
{
|
||||
OVERLAPPED hid_overlap_read = OVERLAPPED();
|
||||
hid_overlap_read.hEvent = CreateEvent(nullptr, true, false, nullptr);
|
||||
|
@ -359,7 +434,7 @@ static int ReadFromHandle(HANDLE& dev_handle, u8* buf)
|
|||
return read;
|
||||
}
|
||||
|
||||
static bool IsWiimote(const std::basic_string<TCHAR>& device_path, WinWriteMethod& method)
|
||||
bool IsWiimote(const std::basic_string<TCHAR>& device_path, WinWriteMethod& method)
|
||||
{
|
||||
HANDLE dev_handle = CreateFile(device_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING,
|
||||
|
@ -393,6 +468,40 @@ static bool IsWiimote(const std::basic_string<TCHAR>& device_path, WinWriteMetho
|
|||
}
|
||||
return false;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
WiimoteScannerWindows::WiimoteScannerWindows()
|
||||
{
|
||||
init_lib();
|
||||
}
|
||||
|
||||
WiimoteScannerWindows::~WiimoteScannerWindows()
|
||||
{
|
||||
// TODO: what do we want here?
|
||||
#if 0
|
||||
ProcessWiimotes(false, [](HANDLE, BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
|
||||
{
|
||||
RemoveWiimote(btdi);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void WiimoteScannerWindows::Update()
|
||||
{
|
||||
if (!s_loaded_ok)
|
||||
return;
|
||||
|
||||
bool forgot_some = false;
|
||||
|
||||
ProcessWiimotes(false, [&](HANDLE, BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT& btdi) {
|
||||
forgot_some |= ForgetWiimote(btdi);
|
||||
});
|
||||
|
||||
// Some hacks that allows disconnects to be detected before connections are handled
|
||||
// workaround for Wiimote 1 moving to slot 2 on temporary disconnect
|
||||
if (forgot_some)
|
||||
Common::SleepCurrentThread(100);
|
||||
}
|
||||
|
||||
// Find and connect Wiimotes.
|
||||
// Does not replace already found Wiimotes even if they are disconnected.
|
||||
|
@ -686,110 +795,6 @@ int WiimoteWindows::IORead(u8* buf)
|
|||
return WiimoteReal::IORead(m_dev_handle, m_hid_overlap_read, buf, m_index);
|
||||
}
|
||||
|
||||
static int IOWritePerSetOutputReport(HANDLE& dev_handle, const u8* buf, size_t len, DWORD* written)
|
||||
{
|
||||
BOOLEAN result = pHidD_SetOutputReport(dev_handle, const_cast<u8*>(buf) + 1, (ULONG)(len - 1));
|
||||
if (!result)
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_SEM_TIMEOUT)
|
||||
{
|
||||
NOTICE_LOG(WIIMOTE, "IOWrite[WWM_SET_OUTPUT_REPORT]: Unable to send data to the Wiimote");
|
||||
}
|
||||
else if (err != ERROR_GEN_FAILURE)
|
||||
{
|
||||
// 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[WWM_SET_OUTPUT_REPORT]: Error: %08x", err);
|
||||
}
|
||||
}
|
||||
|
||||
if (written)
|
||||
{
|
||||
*written = (result ? (DWORD)len : 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int IOWritePerWriteFile(HANDLE& dev_handle, OVERLAPPED& hid_overlap_write,
|
||||
WinWriteMethod& write_method, const u8* buf, size_t len,
|
||||
DWORD* written)
|
||||
{
|
||||
DWORD bytes_written;
|
||||
LPCVOID write_buffer = buf + 1;
|
||||
DWORD bytes_to_write = (DWORD)(len - 1);
|
||||
|
||||
u8 resized_buffer[MAX_PAYLOAD];
|
||||
|
||||
// Resize the buffer, if the underlying HID Class driver needs the buffer to be the size of
|
||||
// HidCaps.OuputReportSize
|
||||
// In case of Wiimote HidCaps.OuputReportSize is 22 Byte.
|
||||
// This is currently needed by the Toshiba Bluetooth Stack.
|
||||
if ((write_method == WWM_WRITE_FILE_LARGEST_REPORT_SIZE) && (MAX_PAYLOAD > len))
|
||||
{
|
||||
std::copy(buf, buf + len, resized_buffer);
|
||||
std::fill(resized_buffer + len, resized_buffer + MAX_PAYLOAD, 0);
|
||||
write_buffer = resized_buffer + 1;
|
||||
bytes_to_write = MAX_PAYLOAD - 1;
|
||||
}
|
||||
|
||||
ResetEvent(hid_overlap_write.hEvent);
|
||||
BOOLEAN result =
|
||||
WriteFile(dev_handle, write_buffer, bytes_to_write, &bytes_written, &hid_overlap_write);
|
||||
if (!result)
|
||||
{
|
||||
const DWORD error = GetLastError();
|
||||
|
||||
switch (error)
|
||||
{
|
||||
case ERROR_INVALID_USER_BUFFER:
|
||||
INFO_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: Falling back to SetOutputReport");
|
||||
write_method = WWM_SET_OUTPUT_REPORT;
|
||||
return IOWritePerSetOutputReport(dev_handle, buf, len, written);
|
||||
case ERROR_IO_PENDING:
|
||||
// Pending is no error!
|
||||
break;
|
||||
default:
|
||||
WARN_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: Error on WriteFile: %08x", error);
|
||||
CancelIo(dev_handle);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (written)
|
||||
{
|
||||
*written = 0;
|
||||
}
|
||||
|
||||
// Wait for completion
|
||||
DWORD wait_result = WaitForSingleObject(hid_overlap_write.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
|
||||
|
||||
if (WAIT_TIMEOUT == wait_result)
|
||||
{
|
||||
WARN_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: A timeout occurred on writing to Wiimote.");
|
||||
CancelIo(dev_handle);
|
||||
return 1;
|
||||
}
|
||||
else if (WAIT_FAILED == wait_result)
|
||||
{
|
||||
WARN_LOG(WIIMOTE, "IOWrite[WWM_WRITE_FILE]: A wait error occurred on writing to Wiimote.");
|
||||
CancelIo(dev_handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (written)
|
||||
{
|
||||
if (!GetOverlappedResult(dev_handle, &hid_overlap_write, written, TRUE))
|
||||
{
|
||||
*written = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// As of https://msdn.microsoft.com/en-us/library/windows/hardware/ff543402(v=vs.85).aspx, WriteFile
|
||||
// is the preferred method
|
||||
// to send output reports to the HID. WriteFile sends an IRP_MJ_WRITE to the HID Class Driver
|
||||
|
@ -961,7 +966,7 @@ bool AttachWiimote(HANDLE hRadio, const BLUETOOTH_RADIO_INFO& radio_info,
|
|||
const DWORD hr = pBluetoothSetServiceState(
|
||||
hRadio, &btdi, &HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE);
|
||||
|
||||
g_connect_times[btdi.Address.ullLong] = std::time(nullptr);
|
||||
s_connect_times[btdi.Address.ullLong] = std::time(nullptr);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
|
@ -985,8 +990,8 @@ bool ForgetWiimote(BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
|
|||
// Sometimes SetServiceState takes a while..
|
||||
auto const avoid_forget_seconds = 5.0;
|
||||
|
||||
auto pair_time = g_connect_times.find(btdi.Address.ullLong);
|
||||
if (pair_time == g_connect_times.end() ||
|
||||
auto pair_time = s_connect_times.find(btdi.Address.ullLong);
|
||||
if (pair_time == s_connect_times.end() ||
|
||||
std::difftime(time(nullptr), pair_time->second) >= avoid_forget_seconds)
|
||||
{
|
||||
// Make Windows forget about device so it will re-find it if visible.
|
||||
|
|
Loading…
Reference in New Issue