Files
itgmania212121/stepmania/src/archutils/Win32/USB.cpp
T

246 lines
6.1 KiB
C++
Raw Normal View History

2003-03-19 20:34:40 +00:00
#include "global.h"
#include "USB.h"
#include "RageLog.h"
#include "RageUtil.h"
#if defined(_MSC_VER)
2004-08-27 20:27:41 +00:00
#pragma comment(lib, "archutils/Win32/ddk/setupapi.lib")
#pragma comment(lib, "archutils/Win32/ddk/hid.lib")
#endif
2003-03-19 20:34:40 +00:00
extern "C" {
2004-08-27 20:27:41 +00:00
#include "archutils/Win32/ddk/setupapi.h"
2003-03-19 20:34:40 +00:00
/* Quiet header warning: */
2004-08-27 20:27:41 +00:00
#include "archutils/Win32/ddk/hidsdi.h"
2003-03-19 20:34:40 +00:00
}
2006-01-22 01:00:06 +00:00
static RString GetUSBDevicePath( int iNum )
2003-03-19 20:34:40 +00:00
{
2006-07-21 18:45:11 +00:00
GUID guid;
HidD_GetHidGuid( &guid );
2003-03-19 20:34:40 +00:00
2006-07-21 18:45:11 +00:00
HDEVINFO DeviceInfo = SetupDiGetClassDevs( &guid, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE) );
2003-03-19 20:34:40 +00:00
2006-07-21 18:45:11 +00:00
SP_DEVICE_INTERFACE_DATA DeviceInterface;
DeviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
2003-03-19 20:34:40 +00:00
2006-07-21 18:45:11 +00:00
if( !SetupDiEnumDeviceInterfaces (DeviceInfo,
NULL, &guid, iNum, &DeviceInterface) )
2003-07-14 06:24:30 +00:00
{
2006-07-21 18:45:11 +00:00
SetupDiDestroyDeviceInfoList( DeviceInfo );
return RString();
2003-07-14 06:24:30 +00:00
}
2003-03-19 20:34:40 +00:00
2006-07-21 18:45:11 +00:00
unsigned long iSize;
SetupDiGetDeviceInterfaceDetail( DeviceInfo, &DeviceInterface, NULL, 0, &iSize, 0 );
2003-03-19 20:34:40 +00:00
2006-07-21 18:45:11 +00:00
PSP_INTERFACE_DEVICE_DETAIL_DATA DeviceDetail = (PSP_INTERFACE_DEVICE_DETAIL_DATA) malloc( iSize );
DeviceDetail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
2003-03-19 20:34:40 +00:00
2006-07-21 18:45:11 +00:00
RString sRet;
if( SetupDiGetDeviceInterfaceDetail(DeviceInfo, &DeviceInterface,
2005-11-23 20:32:32 +00:00
DeviceDetail, iSize, &iSize, NULL) )
2006-07-21 18:45:11 +00:00
sRet = DeviceDetail->DevicePath;
2005-11-23 20:32:32 +00:00
free( DeviceDetail );
2003-03-19 20:34:40 +00:00
2005-11-23 20:32:32 +00:00
SetupDiDestroyDeviceInfoList( DeviceInfo );
2006-07-21 18:45:11 +00:00
return sRet;
2003-03-19 20:34:40 +00:00
}
bool USBDevice::Open( int iVID, int iPID, int iBlockSize, int iNum, void (*pfnInit)(HANDLE) )
2003-03-19 20:34:40 +00:00
{
2006-07-21 18:45:11 +00:00
DWORD iIndex = 0;
2003-03-19 20:34:40 +00:00
2006-07-21 18:45:11 +00:00
RString path;
while( (path = GetUSBDevicePath(iIndex++)) != "" )
{
2005-11-23 20:32:32 +00:00
HANDLE h = CreateFile( path, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
2003-03-19 20:34:40 +00:00
2005-11-23 20:32:32 +00:00
if( h == INVALID_HANDLE_VALUE )
2003-03-19 20:34:40 +00:00
continue;
HIDD_ATTRIBUTES attr;
2005-11-23 20:32:32 +00:00
if( !HidD_GetAttributes(h, &attr) )
2003-07-14 06:24:30 +00:00
{
2005-11-23 20:32:32 +00:00
CloseHandle( h );
2003-03-19 20:34:40 +00:00
continue;
2003-07-14 06:24:30 +00:00
}
2003-03-19 20:34:40 +00:00
2006-07-21 18:45:11 +00:00
if( (iVID != -1 && attr.VendorID != iVID) ||
(iPID != -1 && attr.ProductID != iPID) )
{
CloseHandle( h );
2003-03-19 20:34:40 +00:00
continue; /* This isn't it. */
}
2003-03-19 20:34:40 +00:00
/* The VID and PID match. */
2005-11-23 20:32:32 +00:00
if( iNum-- > 0 )
{
CloseHandle( h );
2003-07-14 06:24:30 +00:00
continue;
}
if( pfnInit )
pfnInit( h );
CloseHandle(h);
2003-07-14 06:24:30 +00:00
2005-11-23 20:32:32 +00:00
m_IO.Open( path, iBlockSize );
2006-07-21 18:45:11 +00:00
return true;
}
2003-03-19 20:34:40 +00:00
2006-07-21 18:45:11 +00:00
return false;
2003-03-19 20:34:40 +00:00
}
2003-07-14 06:24:30 +00:00
bool USBDevice::IsOpen() const
2003-03-19 20:34:40 +00:00
{
2005-11-23 20:32:32 +00:00
return m_IO.IsOpen();
2003-03-19 20:34:40 +00:00
}
2003-05-28 02:35:05 +00:00
2003-03-19 20:34:40 +00:00
int USBDevice::GetPadEvent()
{
2005-11-23 20:32:32 +00:00
if( !IsOpen() )
2003-03-19 20:34:40 +00:00
return -1;
2005-11-23 20:32:32 +00:00
long iBuf;
if( m_IO.read(&iBuf) <= 0 )
2003-07-14 06:24:30 +00:00
return -1;
2003-03-19 20:34:40 +00:00
2006-07-21 18:45:11 +00:00
return iBuf;
2003-07-14 06:24:30 +00:00
}
WindowsFileIO::WindowsFileIO()
{
2005-11-23 20:32:32 +00:00
ZeroMemory( &m_Overlapped, sizeof(m_Overlapped) );
m_Handle = INVALID_HANDLE_VALUE;
m_pBuffer = NULL;
2003-07-14 06:24:30 +00:00
}
WindowsFileIO::~WindowsFileIO()
{
2005-11-23 20:32:32 +00:00
if( m_Handle != INVALID_HANDLE_VALUE )
CloseHandle( m_Handle );
delete[] m_pBuffer;
2003-07-14 06:24:30 +00:00
}
2006-01-22 01:00:06 +00:00
bool WindowsFileIO::Open( RString path, int iBlockSize )
2003-07-14 06:24:30 +00:00
{
LOG->Trace( "WindowsFileIO::open(%s)", path.c_str() );
2005-11-23 20:32:32 +00:00
m_iBlockSize = iBlockSize;
2003-07-14 06:24:30 +00:00
2005-11-23 20:32:32 +00:00
if( m_pBuffer )
delete[] m_pBuffer;
m_pBuffer = new char[m_iBlockSize];
2003-07-14 06:24:30 +00:00
2005-11-23 20:32:32 +00:00
if( m_Handle != INVALID_HANDLE_VALUE )
CloseHandle( m_Handle );
2003-07-14 06:24:30 +00:00
2005-11-23 20:32:32 +00:00
m_Handle = CreateFile( path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL );
2003-07-14 06:24:30 +00:00
2005-11-23 20:32:32 +00:00
if( m_Handle == INVALID_HANDLE_VALUE )
2003-07-14 06:24:30 +00:00
return false;
queue_read();
return true;
}
void WindowsFileIO::queue_read()
{
/* Request feedback from the device. */
2005-11-23 20:32:32 +00:00
unsigned long iRead;
ReadFile( m_Handle, m_pBuffer, m_iBlockSize, &iRead, &m_Overlapped );
2003-07-14 06:24:30 +00:00
}
2005-11-23 20:32:32 +00:00
int WindowsFileIO::finish_read( void *p )
2003-07-14 06:24:30 +00:00
{
2005-11-23 20:32:32 +00:00
LOG->Trace( "this %p, %p", this, p );
/* We do; get the result. It'll go into the original m_pBuffer
* we supplied on the original call; that's why m_pBuffer is a
2003-07-14 06:24:30 +00:00
* member instead of a local. */
2006-07-21 18:45:11 +00:00
unsigned long iCnt;
int iRet = GetOverlappedResult( m_Handle, &m_Overlapped, &iCnt, FALSE );
2003-07-14 06:24:30 +00:00
2006-07-21 18:45:11 +00:00
if( iRet == 0 && (GetLastError() == ERROR_IO_PENDING || GetLastError() == ERROR_IO_INCOMPLETE) )
2003-07-14 06:24:30 +00:00
return -1;
queue_read();
2005-11-23 20:32:32 +00:00
if( iRet == 0 )
2003-07-14 06:24:30 +00:00
{
2005-11-23 20:32:32 +00:00
LOG->Warn( werr_ssprintf(GetLastError(), "Error reading USB device") );
2006-07-21 18:45:11 +00:00
return -1;
}
2003-03-19 20:34:40 +00:00
2005-11-23 20:34:10 +00:00
memcpy( p, m_pBuffer, iCnt );
2005-11-23 22:42:24 +00:00
return iCnt;
2003-07-14 06:24:30 +00:00
}
2005-11-23 20:32:32 +00:00
int WindowsFileIO::read( void *p )
2003-07-14 06:24:30 +00:00
{
LOG->Trace( "WindowsFileIO::read()" );
2003-03-19 20:34:40 +00:00
/* See if we have a response for our request (which we may
* have made on a previous call): */
2006-07-21 18:45:11 +00:00
if( WaitForSingleObjectEx(m_Handle, 0, TRUE) == WAIT_TIMEOUT )
2003-03-19 20:34:40 +00:00
return -1;
2003-07-14 06:24:30 +00:00
return finish_read(p);
}
int WindowsFileIO::read_several(const vector<WindowsFileIO *> &sources, void *p, int &actual, float timeout)
{
HANDLE *Handles = new HANDLE[sources.size()];
for( unsigned i = 0; i < sources.size(); ++i )
2005-11-23 20:32:32 +00:00
Handles[i] = sources[i]->m_Handle;
2003-07-14 06:24:30 +00:00
int ret = WaitForMultipleObjectsEx( sources.size(), Handles, false, int(timeout * 1000), true);
delete[] Handles;
if( ret == -1 )
{
LOG->Trace( werr_ssprintf(GetLastError(), "WaitForMultipleObjectsEx failed") );
2003-03-19 20:34:40 +00:00
return -1;
2003-07-14 06:24:30 +00:00
}
2003-03-19 20:34:40 +00:00
2003-07-14 06:24:30 +00:00
if( ret >= int(WAIT_OBJECT_0) && ret < int(WAIT_OBJECT_0+sources.size()) )
{
actual = ret - WAIT_OBJECT_0;
return sources[actual]->finish_read(p);
}
2003-03-19 20:34:40 +00:00
2003-07-14 06:24:30 +00:00
return 0;
}
bool WindowsFileIO::IsOpen() const
{
2005-11-23 20:32:32 +00:00
return m_Handle != INVALID_HANDLE_VALUE;
2003-03-19 20:34:40 +00:00
}
/*
2005-11-23 20:32:32 +00:00
* (c) 2002-2005 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/