pcsx2/plugins/LilyPad/HidDevice.cpp

135 lines
5.2 KiB
C++

/* LilyPad - Pad plugin for PS2 Emulator
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
*
* PCSX2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Found- ation, either version 3 of the License, or (at your option)
* any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Global.h"
#include "HidDevice.h"
#include <setupapi.h>
// Tons of annoying junk to avoid the hid dependencies, so no one has to download the
// DDK to compile.
#define HIDP_STATUS_SUCCESS 0x110000
struct HIDD_ATTRIBUTES {
ULONG Size;
USHORT VendorID;
USHORT ProductID;
USHORT VersionNumber;
};
struct HIDP_PREPARSED_DATA;
typedef BOOLEAN (__stdcall *_HidD_GetAttributes) (HANDLE HidDeviceObject, HIDD_ATTRIBUTES *Attributes);
typedef void (__stdcall *_HidD_GetHidGuid) (GUID* HidGuid);
typedef BOOLEAN (__stdcall *_HidD_GetPreparsedData) (HANDLE HidDeviceObject, HIDP_PREPARSED_DATA **PreparsedData);
typedef NTSTATUS (__stdcall *_HidP_GetCaps) (HIDP_PREPARSED_DATA* PreparsedData, HIDP_CAPS *caps);
typedef BOOLEAN (__stdcall *_HidD_FreePreparsedData) (HIDP_PREPARSED_DATA *PreparsedData);
typedef BOOLEAN (__stdcall *_HidD_GetFeature) (HANDLE HidDeviceObject, PVOID ReportBuffer, ULONG ReportBufferLength);
typedef BOOLEAN (__stdcall *_HidD_SetFeature) (HANDLE HidDeviceObject, PVOID ReportBuffer, ULONG ReportBufferLength);
GUID GUID_DEVINTERFACE_HID;
_HidD_GetHidGuid pHidD_GetHidGuid;
_HidD_GetAttributes pHidD_GetAttributes;
_HidD_GetPreparsedData pHidD_GetPreparsedData;
_HidP_GetCaps pHidP_GetCaps;
_HidD_FreePreparsedData pHidD_FreePreparsedData;
_HidD_GetFeature pHidD_GetFeature;
_HidD_SetFeature pHidD_SetFeature;
HMODULE hModHid = 0;
int InitHid() {
if (hModHid) {
return 1;
}
hModHid = LoadLibraryA("hid.dll");
if (hModHid) {
if ((pHidD_GetHidGuid = (_HidD_GetHidGuid) GetProcAddress(hModHid, "HidD_GetHidGuid")) &&
(pHidD_GetAttributes = (_HidD_GetAttributes) GetProcAddress(hModHid, "HidD_GetAttributes")) &&
(pHidD_GetPreparsedData = (_HidD_GetPreparsedData) GetProcAddress(hModHid, "HidD_GetPreparsedData")) &&
(pHidP_GetCaps = (_HidP_GetCaps) GetProcAddress(hModHid, "HidP_GetCaps")) &&
(pHidD_FreePreparsedData = (_HidD_FreePreparsedData) GetProcAddress(hModHid, "HidD_FreePreparsedData")) &&
(pHidD_GetFeature = (_HidD_GetFeature) GetProcAddress(hModHid, "HidD_GetFeature")) &&
(pHidD_SetFeature = (_HidD_SetFeature) GetProcAddress(hModHid, "HidD_SetFeature"))) {
pHidD_GetHidGuid(&GUID_DEVINTERFACE_HID);
return 1;
}
UninitHid();
}
return 0;
}
int FindHids(HidDeviceInfo **foundDevs, int vid, int pid) {
if (!InitHid()) return 0;
int numFoundDevs = 0;
*foundDevs = 0;
HDEVINFO hdev = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_HID, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hdev != INVALID_HANDLE_VALUE) {
SP_DEVICE_INTERFACE_DATA devInterfaceData;
devInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
for (int i=0; SetupDiEnumDeviceInterfaces(hdev, 0, &GUID_DEVINTERFACE_HID, i, &devInterfaceData); i++) {
DWORD size = 0;
SetupDiGetDeviceInterfaceDetail(hdev, &devInterfaceData, 0, 0, &size, 0);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || !size) continue;
SP_DEVICE_INTERFACE_DETAIL_DATA *devInterfaceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA *) malloc(size);
if (!devInterfaceDetails) continue;
devInterfaceDetails->cbSize = sizeof(*devInterfaceDetails);
SP_DEVINFO_DATA devInfoData;
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiGetDeviceInterfaceDetail(hdev, &devInterfaceData, devInterfaceDetails, size, &size, &devInfoData)) continue;
HANDLE hfile = CreateFileW(devInterfaceDetails->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (hfile != INVALID_HANDLE_VALUE) {
HIDD_ATTRIBUTES attributes;
attributes.Size = sizeof(attributes);
if (pHidD_GetAttributes(hfile, &attributes)) {
if (attributes.VendorID == vid && attributes.ProductID == pid) {
HIDP_PREPARSED_DATA *pData;
HIDP_CAPS caps;
if (pHidD_GetPreparsedData(hfile, &pData)) {
if (HIDP_STATUS_SUCCESS == pHidP_GetCaps(pData, &caps)) {
if (numFoundDevs % 32 == 0) {
*foundDevs = (HidDeviceInfo*) realloc(*foundDevs, sizeof(HidDeviceInfo) * (32 + numFoundDevs));
}
HidDeviceInfo *dev = &foundDevs[0][numFoundDevs++];
dev->caps = caps;
dev->vid = attributes.VendorID;
dev->pid = attributes.ProductID;
dev->path = wcsdup(devInterfaceDetails->DevicePath);
}
pHidD_FreePreparsedData(pData);
}
}
}
CloseHandle(hfile);
}
free(devInterfaceDetails);
}
SetupDiDestroyDeviceInfoList(hdev);
}
return numFoundDevs;
}
void UninitHid() {
if (hModHid) {
FreeLibrary(hModHid);
hModHid = 0;
}
}