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 "SDeviceSignature.hpp"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define _WIN32_LEAN_AND_MEAN 1
|
||||||
|
#include <windows.h>
|
||||||
|
#include <Dbt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -147,6 +153,47 @@ public:
|
||||||
virtual void deviceConnected(CDeviceToken&) {}
|
virtual void deviceConnected(CDeviceToken&) {}
|
||||||
virtual void deviceDisconnected(CDeviceToken&, CDeviceBase*) {}
|
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 */
|
/* Manual device scanning */
|
||||||
virtual bool scanNow()=0;
|
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 */
|
/* Platform-specific constructor */
|
||||||
|
|
|
@ -5,7 +5,7 @@ CONFIG += console
|
||||||
unix:QMAKE_CXXFLAGS += -stdlib=libc++
|
unix:QMAKE_CXXFLAGS += -stdlib=libc++
|
||||||
unix:LIBS += -std=c++11 -stdlib=libc++ -lc++abi
|
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:CONFIG += link_pkgconfig
|
||||||
#unix:!macx:PKGCONFIG += x11
|
#unix:!macx:PKGCONFIG += x11
|
||||||
|
|
|
@ -56,6 +56,12 @@ parseState(SDolphinControllerState* stateOut, uint8_t* payload, bool& rumble)
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CDolphinSmashAdapter::initialCycle()
|
||||||
|
{
|
||||||
|
uint8_t handshakePayload[] = {0x13};
|
||||||
|
sendUSBInterruptTransfer(0, handshakePayload, sizeof(handshakePayload));
|
||||||
|
}
|
||||||
|
|
||||||
void CDolphinSmashAdapter::transferCycle()
|
void CDolphinSmashAdapter::transferCycle()
|
||||||
{
|
{
|
||||||
uint8_t payload[37];
|
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()
|
void CDolphinSmashAdapter::finalCycle()
|
||||||
{
|
{
|
||||||
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
|
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#define _WIN32_LEAN_AND_MEAN 1
|
#define _WIN32_LEAN_AND_MEAN 1
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <winusb.h>
|
#include <winusb.h>
|
||||||
|
#include <usb100.h>
|
||||||
|
#include <Winusbio.h>
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
|
@ -37,8 +39,8 @@ class CHIDDeviceWinUSB final : public IHIDDevice
|
||||||
{
|
{
|
||||||
ULONG lengthTransferred = 0;
|
ULONG lengthTransferred = 0;
|
||||||
if (!WinUsb_WritePipe(m_usbHandle, m_usbIntfOutPipe, (PUCHAR)data,
|
if (!WinUsb_WritePipe(m_usbHandle, m_usbIntfOutPipe, (PUCHAR)data,
|
||||||
(ULONG)length, &lengthTransferred, NULL)
|
(ULONG)length, &lengthTransferred, NULL) ||
|
||||||
|| lengthTransferred != length)
|
lengthTransferred != length)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -72,20 +74,22 @@ class CHIDDeviceWinUSB final : public IHIDDevice
|
||||||
OPEN_EXISTING,
|
OPEN_EXISTING,
|
||||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
||||||
NULL);
|
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",
|
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
|
||||||
device->m_token.getProductName().c_str(),
|
device->m_token.getProductName().c_str(),
|
||||||
device->m_devPath, GetLastError());
|
device->m_devPath.c_str(), GetLastError());
|
||||||
device->m_devImp.deviceError(errStr);
|
device->m_devImp.deviceError(errStr);
|
||||||
lk.unlock();
|
lk.unlock();
|
||||||
device->m_initCond.notify_one();
|
device->m_initCond.notify_one();
|
||||||
return;
|
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",
|
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
|
||||||
device->m_token.getProductName().c_str(),
|
device->m_token.getProductName().c_str(),
|
||||||
device->m_devPath, GetLastError());
|
device->m_devPath.c_str(), GetLastError());
|
||||||
device->m_devImp.deviceError(errStr);
|
device->m_devImp.deviceError(errStr);
|
||||||
lk.unlock();
|
lk.unlock();
|
||||||
device->m_initCond.notify_one();
|
device->m_initCond.notify_one();
|
||||||
|
@ -93,6 +97,32 @@ class CHIDDeviceWinUSB final : public IHIDDevice
|
||||||
return;
|
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 */
|
/* Return control to main thread */
|
||||||
device->m_runningTransferLoop = true;
|
device->m_runningTransferLoop = true;
|
||||||
lk.unlock();
|
lk.unlock();
|
||||||
|
|
|
@ -20,15 +20,13 @@ class CHIDListenerWinUSB final : public IHIDListener
|
||||||
{
|
{
|
||||||
CDeviceFinder& m_finder;
|
CDeviceFinder& m_finder;
|
||||||
|
|
||||||
std::thread* m_setupThread;
|
|
||||||
bool m_setupRunning;
|
|
||||||
bool m_scanningEnabled;
|
bool m_scanningEnabled;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reference: https://github.com/pbatard/libwdi/blob/master/libwdi/libwdi.c
|
* Reference: https://github.com/pbatard/libwdi/blob/master/libwdi/libwdi.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void _pollDevices()
|
void _pollDevices(const char* pathFilter)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Don't ask */
|
/* Don't ask */
|
||||||
|
@ -133,6 +131,13 @@ class CHIDListenerWinUSB final : public IHIDListener
|
||||||
&devpropType, (BYTE*)manufW, 1024, &manufSz, 0);
|
&devpropType, (BYTE*)manufW, 1024, &manufSz, 0);
|
||||||
wcstombs(manuf, manufW, manufSz / 2);
|
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!! */
|
/* Whew!! that's a single device enumerated!! */
|
||||||
if (!m_finder._hasToken(DeviceInterfaceDetailData.wtf.DevicePath))
|
if (!m_finder._hasToken(DeviceInterfaceDetailData.wtf.DevicePath))
|
||||||
m_finder._insertToken(CDeviceToken(CDeviceToken::DEVTYPE_USB,
|
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:
|
public:
|
||||||
CHIDListenerWinUSB(CDeviceFinder& finder)
|
CHIDListenerWinUSB(CDeviceFinder& finder)
|
||||||
: m_finder(finder)
|
: m_finder(finder)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Initial HID Device Add */
|
/* Initial HID Device Add */
|
||||||
_pollDevices();
|
_pollDevices(NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~CHIDListenerWinUSB()
|
~CHIDListenerWinUSB()
|
||||||
{
|
{}
|
||||||
m_setupRunning = false;
|
|
||||||
m_setupThread->join();
|
|
||||||
delete m_setupThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Automatic device scanning */
|
/* Automatic device scanning */
|
||||||
bool startScanning()
|
bool startScanning()
|
||||||
|
@ -189,7 +176,26 @@ public:
|
||||||
/* Manual device scanning */
|
/* Manual device scanning */
|
||||||
bool scanNow()
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ class IHIDDevice
|
||||||
virtual size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)=0;
|
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;
|
virtual bool _sendHIDReport(const uint8_t* data, size_t length)=0;
|
||||||
public:
|
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__
|
#if __APPLE__
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
@ -10,7 +11,6 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <initguid.h>
|
#include <initguid.h>
|
||||||
#include <Usbiodef.h>
|
#include <Usbiodef.h>
|
||||||
#include <Dbt.h>
|
|
||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#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)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -77,40 +157,10 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
CFRunLoopRun();
|
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
|
#endif
|
||||||
|
|
||||||
//delete ctx;
|
//delete ctx;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue