mirror of https://github.com/AxioDL/boo.git
WinUSB API implemented!!
This commit is contained in:
parent
e2d7030bb4
commit
4d1ec9f94b
|
@ -9,6 +9,12 @@
|
|||
#include "SDeviceSignature.hpp"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _WIN32_LEAN_AND_MEAN 1
|
||||
#include <windows.h>
|
||||
#include <Dbt.h>
|
||||
#endif
|
||||
|
||||
namespace boo
|
||||
{
|
||||
|
||||
|
@ -147,6 +153,47 @@ public:
|
|||
virtual void deviceConnected(CDeviceToken&) {}
|
||||
virtual void deviceDisconnected(CDeviceToken&, CDeviceBase*) {}
|
||||
|
||||
#if _WIN32
|
||||
/* Windows-specific WM_DEVICECHANGED handler */
|
||||
static LRESULT winDevChangedHandler(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
PDEV_BROADCAST_HDR dbh = (PDEV_BROADCAST_HDR)lParam;
|
||||
PDEV_BROADCAST_DEVICEINTERFACE dbhi = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
|
||||
CDeviceFinder* finder = instance();
|
||||
if (!finder)
|
||||
return 0;
|
||||
|
||||
if (wParam == DBT_DEVICEARRIVAL)
|
||||
{
|
||||
if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
char devPath[1024];
|
||||
wcstombs(devPath, dbhi->dbcc_name, 1024);
|
||||
finder->m_listener->_extDevConnect(devPath);
|
||||
#else
|
||||
finder->m_listener->_extDevConnect(dbhi->dbcc_name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (wParam == DBT_DEVICEREMOVECOMPLETE)
|
||||
{
|
||||
if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
char devPath[1024];
|
||||
wcstombs(devPath, dbhi->dbcc_name, 1024);
|
||||
finder->m_listener->_extDevDisconnect(devPath);
|
||||
#else
|
||||
finder->m_listener->_extDevDisconnect(dbhi->dbcc_name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,12 @@ public:
|
|||
/* Manual device scanning */
|
||||
virtual bool scanNow()=0;
|
||||
|
||||
#if _WIN32
|
||||
/* External listener implementation (for Windows) */
|
||||
virtual bool _extDevConnect(const char* path)=0;
|
||||
virtual bool _extDevDisconnect(const char* path)=0;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
/* Platform-specific constructor */
|
||||
|
|
|
@ -5,7 +5,7 @@ CONFIG += console
|
|||
unix:QMAKE_CXXFLAGS += -stdlib=libc++
|
||||
unix:LIBS += -std=c++11 -stdlib=libc++ -lc++abi
|
||||
|
||||
win32:LIBS += Setupapi.lib winusb.lib User32.lib
|
||||
win32:LIBS += Setupapi.lib winusb.lib User32.lib /SUBSYSTEM:Windows
|
||||
|
||||
#unix:!macx:CONFIG += link_pkgconfig
|
||||
#unix:!macx:PKGCONFIG += x11
|
||||
|
|
|
@ -56,6 +56,12 @@ parseState(SDolphinControllerState* stateOut, uint8_t* payload, bool& rumble)
|
|||
return type;
|
||||
}
|
||||
|
||||
void CDolphinSmashAdapter::initialCycle()
|
||||
{
|
||||
uint8_t handshakePayload[] = {0x13};
|
||||
sendUSBInterruptTransfer(0, handshakePayload, sizeof(handshakePayload));
|
||||
}
|
||||
|
||||
void CDolphinSmashAdapter::transferCycle()
|
||||
{
|
||||
uint8_t payload[37];
|
||||
|
@ -107,12 +113,6 @@ void CDolphinSmashAdapter::transferCycle()
|
|||
}
|
||||
}
|
||||
|
||||
void CDolphinSmashAdapter::initialCycle()
|
||||
{
|
||||
uint8_t handshakePayload[] = {0x13};
|
||||
sendUSBInterruptTransfer(0, handshakePayload, sizeof(handshakePayload));
|
||||
}
|
||||
|
||||
void CDolphinSmashAdapter::finalCycle()
|
||||
{
|
||||
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#define _WIN32_LEAN_AND_MEAN 1
|
||||
#include <windows.h>
|
||||
#include <winusb.h>
|
||||
#include <usb100.h>
|
||||
#include <Winusbio.h>
|
||||
|
||||
namespace boo
|
||||
{
|
||||
|
@ -37,8 +39,8 @@ class CHIDDeviceWinUSB final : public IHIDDevice
|
|||
{
|
||||
ULONG lengthTransferred = 0;
|
||||
if (!WinUsb_WritePipe(m_usbHandle, m_usbIntfOutPipe, (PUCHAR)data,
|
||||
(ULONG)length, &lengthTransferred, NULL)
|
||||
|| lengthTransferred != length)
|
||||
(ULONG)length, &lengthTransferred, NULL) ||
|
||||
lengthTransferred != length)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -72,20 +74,22 @@ class CHIDDeviceWinUSB final : public IHIDDevice
|
|||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
if (INVALID_HANDLE_VALUE == device->m_devHandle) {
|
||||
if (INVALID_HANDLE_VALUE == device->m_devHandle)
|
||||
{
|
||||
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
|
||||
device->m_token.getProductName().c_str(),
|
||||
device->m_devPath, GetLastError());
|
||||
device->m_devPath.c_str(), GetLastError());
|
||||
device->m_devImp.deviceError(errStr);
|
||||
lk.unlock();
|
||||
device->m_initCond.notify_one();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WinUsb_Initialize(device->m_devHandle, &device->m_usbHandle)) {
|
||||
if (!WinUsb_Initialize(device->m_devHandle, &device->m_usbHandle))
|
||||
{
|
||||
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
|
||||
device->m_token.getProductName().c_str(),
|
||||
device->m_devPath, GetLastError());
|
||||
device->m_devPath.c_str(), GetLastError());
|
||||
device->m_devImp.deviceError(errStr);
|
||||
lk.unlock();
|
||||
device->m_initCond.notify_one();
|
||||
|
@ -93,6 +97,32 @@ class CHIDDeviceWinUSB final : public IHIDDevice
|
|||
return;
|
||||
}
|
||||
|
||||
/* Enumerate device pipes */
|
||||
USB_INTERFACE_DESCRIPTOR ifDesc = {0};
|
||||
if (!WinUsb_QueryInterfaceSettings(device->m_usbHandle, 0, &ifDesc))
|
||||
{
|
||||
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
|
||||
device->m_token.getProductName().c_str(),
|
||||
device->m_devPath.c_str(), GetLastError());
|
||||
device->m_devImp.deviceError(errStr);
|
||||
lk.unlock();
|
||||
device->m_initCond.notify_one();
|
||||
CloseHandle(device->m_devHandle);
|
||||
return;
|
||||
}
|
||||
for (i=0 ; i<ifDesc.bNumEndpoints ; ++i)
|
||||
{
|
||||
WINUSB_PIPE_INFORMATION pipeDesc;
|
||||
WinUsb_QueryPipe(device->m_usbHandle, 0, i, &pipeDesc);
|
||||
if (pipeDesc.PipeType == UsbdPipeTypeInterrupt)
|
||||
{
|
||||
if (USB_ENDPOINT_DIRECTION_IN(pipeDesc.PipeId))
|
||||
device->m_usbIntfInPipe = pipeDesc.PipeId;
|
||||
else
|
||||
device->m_usbIntfOutPipe = pipeDesc.PipeId;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return control to main thread */
|
||||
device->m_runningTransferLoop = true;
|
||||
lk.unlock();
|
||||
|
|
|
@ -20,15 +20,13 @@ class CHIDListenerWinUSB final : public IHIDListener
|
|||
{
|
||||
CDeviceFinder& m_finder;
|
||||
|
||||
std::thread* m_setupThread;
|
||||
bool m_setupRunning;
|
||||
bool m_scanningEnabled;
|
||||
|
||||
/*
|
||||
* Reference: https://github.com/pbatard/libwdi/blob/master/libwdi/libwdi.c
|
||||
*/
|
||||
|
||||
void _pollDevices()
|
||||
void _pollDevices(const char* pathFilter)
|
||||
{
|
||||
|
||||
/* Don't ask */
|
||||
|
@ -133,6 +131,13 @@ class CHIDListenerWinUSB final : public IHIDListener
|
|||
&devpropType, (BYTE*)manufW, 1024, &manufSz, 0);
|
||||
wcstombs(manuf, manufW, manufSz / 2);
|
||||
|
||||
/* Store as a shouting string (to keep hash-lookups consistent) */
|
||||
CharUpperA(DeviceInterfaceDetailData.wtf.DevicePath);
|
||||
|
||||
/* Filter to specific device (provided by hotplug event) */
|
||||
if (pathFilter && strcmp(pathFilter, DeviceInterfaceDetailData.wtf.DevicePath))
|
||||
continue;
|
||||
|
||||
/* Whew!! that's a single device enumerated!! */
|
||||
if (!m_finder._hasToken(DeviceInterfaceDetailData.wtf.DevicePath))
|
||||
m_finder._insertToken(CDeviceToken(CDeviceToken::DEVTYPE_USB,
|
||||
|
@ -145,34 +150,16 @@ class CHIDListenerWinUSB final : public IHIDListener
|
|||
|
||||
}
|
||||
|
||||
static void _setupProc(CHIDListenerWinUSB* listener)
|
||||
{
|
||||
while (listener->m_setupRunning)
|
||||
{
|
||||
if (listener->m_scanningEnabled)
|
||||
listener->_pollDevices();
|
||||
|
||||
/* Due to NT derpiness, this needs to be a periodic poll */
|
||||
Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
CHIDListenerWinUSB(CDeviceFinder& finder)
|
||||
: m_finder(finder)
|
||||
{
|
||||
|
||||
/* Initial HID Device Add */
|
||||
_pollDevices();
|
||||
|
||||
_pollDevices(NULL);
|
||||
}
|
||||
|
||||
~CHIDListenerWinUSB()
|
||||
{
|
||||
m_setupRunning = false;
|
||||
m_setupThread->join();
|
||||
delete m_setupThread;
|
||||
}
|
||||
{}
|
||||
|
||||
/* Automatic device scanning */
|
||||
bool startScanning()
|
||||
|
@ -189,7 +176,26 @@ public:
|
|||
/* Manual device scanning */
|
||||
bool scanNow()
|
||||
{
|
||||
_pollDevices();
|
||||
_pollDevices(NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _extDevConnect(const char* path)
|
||||
{
|
||||
char upperPath[1024];
|
||||
strcpy_s(upperPath, 1024, path);
|
||||
CharUpperA(upperPath);
|
||||
if (m_scanningEnabled && !m_finder._hasToken(upperPath))
|
||||
_pollDevices(upperPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _extDevDisconnect(const char* path)
|
||||
{
|
||||
char upperPath[1024];
|
||||
strcpy_s(upperPath, 1024, path);
|
||||
CharUpperA(upperPath);
|
||||
m_finder._removeToken(upperPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class IHIDDevice
|
|||
virtual size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)=0;
|
||||
virtual bool _sendHIDReport(const uint8_t* data, size_t length)=0;
|
||||
public:
|
||||
inline virtual ~IHIDDevice() {};
|
||||
inline virtual ~IHIDDevice() {}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
116
test/main.cpp
116
test/main.cpp
|
@ -1,3 +1,4 @@
|
|||
#define _CRT_SECURE_NO_WARNINGS 1
|
||||
|
||||
#if __APPLE__
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
@ -10,7 +11,6 @@
|
|||
#include <windows.h>
|
||||
#include <initguid.h>
|
||||
#include <Usbiodef.h>
|
||||
#include <Dbt.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
@ -61,6 +61,86 @@ public:
|
|||
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
|
||||
/* This simple 'test' console app needs a full windows
|
||||
* message loop for receiving device connection events
|
||||
*/
|
||||
static const DEV_BROADCAST_DEVICEINTERFACE_A HOTPLUG_CONF =
|
||||
{
|
||||
sizeof(DEV_BROADCAST_DEVICEINTERFACE_A),
|
||||
DBT_DEVTYP_DEVICEINTERFACE,
|
||||
0,
|
||||
GUID_DEVINTERFACE_USB_DEVICE
|
||||
};
|
||||
|
||||
LRESULT CALLBACK WindowProc(
|
||||
_In_ HWND hwnd,
|
||||
_In_ UINT uMsg,
|
||||
_In_ WPARAM wParam,
|
||||
_In_ LPARAM lParam
|
||||
)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_CREATE:
|
||||
/* Register hotplug notification with windows */
|
||||
RegisterDeviceNotificationA(hwnd, (LPVOID)&HOTPLUG_CONF, DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
return 0;
|
||||
|
||||
case WM_DEVICECHANGE:
|
||||
return boo::CDeviceFinder::winDevChangedHandler(wParam, lParam);
|
||||
|
||||
default:
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
int APIENTRY wWinMain(
|
||||
_In_ HINSTANCE hInstance,
|
||||
_In_ HINSTANCE,
|
||||
_In_ LPTSTR,
|
||||
_In_ int
|
||||
)
|
||||
{
|
||||
AllocConsole();
|
||||
freopen("CONOUT$", "w", stdout);
|
||||
|
||||
WNDCLASS wndClass =
|
||||
{
|
||||
0,
|
||||
WindowProc,
|
||||
0,
|
||||
0,
|
||||
hInstance,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
L"BooTestWindow"
|
||||
};
|
||||
|
||||
RegisterClassW(&wndClass);
|
||||
|
||||
boo::CTestDeviceFinder finder;
|
||||
finder.startScanning();
|
||||
|
||||
HWND hwnd = CreateWindowW(L"BooTestWindow", L"BooTest", WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
NULL, NULL, hInstance, NULL);
|
||||
|
||||
/* Pump messages */
|
||||
MSG msg = {0};
|
||||
while (GetMessage(&msg, hwnd, 0, 0))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
|
||||
|
@ -77,40 +157,10 @@ int main(int argc, char** argv)
|
|||
|
||||
#if __APPLE__
|
||||
CFRunLoopRun();
|
||||
#elif _WIN32
|
||||
|
||||
/* Register hotplug notification with windows */
|
||||
DEV_BROADCAST_DEVICEINTERFACE_A hotplugConf =
|
||||
{
|
||||
sizeof(DEV_BROADCAST_DEVICEINTERFACE_A),
|
||||
DBT_DEVTYP_DEVICEINTERFACE,
|
||||
0,
|
||||
GUID_DEVINTERFACE_USB_DEVICE
|
||||
};
|
||||
HWND consoleWnd = GetConsoleWindow();
|
||||
HDEVNOTIFY notHandle = RegisterDeviceNotificationA(consoleWnd, &hotplugConf, DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
|
||||
MSG recvMsg;
|
||||
while (GetMessage(&recvMsg, consoleWnd, 0, 0))
|
||||
{
|
||||
printf("MSG: %d\n", recvMsg.message);
|
||||
switch (recvMsg.message)
|
||||
{
|
||||
case WM_DEVICECHANGE:
|
||||
printf("DEVICECHANGE!!\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
TranslateMessage(&recvMsg);
|
||||
DispatchMessage(&recvMsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
while (true) {sleep(1);}
|
||||
#endif
|
||||
|
||||
//delete ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue