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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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