WinUSB API implemented!!

This commit is contained in:
Jack Andersen 2015-05-03 18:28:07 -10:00
parent e2d7030bb4
commit 4d1ec9f94b
8 changed files with 210 additions and 71 deletions

View File

@ -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
{
@ -146,6 +152,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
};

View File

@ -23,6 +23,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
};

View File

@ -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

View File

@ -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};

View File

@ -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();

View File

@ -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;
}

View File

@ -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() {}
};
}

View File

@ -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