This commit is contained in:
Glenn Maynard
2003-07-14 06:24:30 +00:00
parent 647c96ecac
commit da6685a3a4
2 changed files with 162 additions and 81 deletions
+128 -69
View File
@@ -15,7 +15,7 @@ extern "C" {
#pragma warning( pop ) #pragma warning( pop )
} }
static char *GetUSBDevicePath (int num) static CString GetUSBDevicePath (int num)
{ {
GUID guid; GUID guid;
HidD_GetHidGuid(&guid); HidD_GetHidGuid(&guid);
@@ -26,132 +26,191 @@ static char *GetUSBDevicePath (int num)
SP_DEVICE_INTERFACE_DATA DeviceInterface; SP_DEVICE_INTERFACE_DATA DeviceInterface;
DeviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); DeviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
char *ret = NULL;
PSP_INTERFACE_DEVICE_DETAIL_DATA DeviceDetail = NULL;
if (!SetupDiEnumDeviceInterfaces (DeviceInfo, if (!SetupDiEnumDeviceInterfaces (DeviceInfo,
NULL, &guid, num, &DeviceInterface)) NULL, &guid, num, &DeviceInterface))
goto err; {
SetupDiDestroyDeviceInfoList (DeviceInfo);
return "";
}
unsigned long size; unsigned long size;
SetupDiGetDeviceInterfaceDetail (DeviceInfo, &DeviceInterface, NULL, 0, &size, 0); SetupDiGetDeviceInterfaceDetail (DeviceInfo, &DeviceInterface, NULL, 0, &size, 0);
DeviceDetail = (PSP_INTERFACE_DEVICE_DETAIL_DATA) malloc(size); PSP_INTERFACE_DEVICE_DETAIL_DATA DeviceDetail = (PSP_INTERFACE_DEVICE_DETAIL_DATA) malloc(size);
DeviceDetail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); DeviceDetail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
CString ret;
if (SetupDiGetDeviceInterfaceDetail (DeviceInfo, &DeviceInterface, if (SetupDiGetDeviceInterfaceDetail (DeviceInfo, &DeviceInterface,
DeviceDetail, size, &size, NULL)) DeviceDetail, size, &size, NULL))
{ ret = DeviceDetail->DevicePath;
ret = strdup(DeviceDetail->DevicePath);
}
err:
SetupDiDestroyDeviceInfoList (DeviceInfo);
free(DeviceDetail); free(DeviceDetail);
SetupDiDestroyDeviceInfoList (DeviceInfo);
return ret; return ret;
} }
static HANDLE OpenUSB (int VID, int PID, int num)
bool USBDevice::Open(int VID, int PID, int blocksize, int num)
{ {
DWORD index = 0; DWORD index = 0;
char *path; CString path;
HANDLE h = INVALID_HANDLE_VALUE; while ((path = GetUSBDevicePath (index++)) != "")
while ((path = GetUSBDevicePath (index++)) != NULL)
{ {
if(h != INVALID_HANDLE_VALUE) HANDLE h = CreateFile (path, GENERIC_READ,
CloseHandle (h); FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
h = CreateFile (path, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
free(path);
if(h == INVALID_HANDLE_VALUE) if(h == INVALID_HANDLE_VALUE)
continue; continue;
HIDD_ATTRIBUTES attr; HIDD_ATTRIBUTES attr;
if (!HidD_GetAttributes (h, &attr)) if (!HidD_GetAttributes (h, &attr))
{
CloseHandle(h);
continue; continue;
}
CloseHandle(h);
if ((VID != -1 && attr.VendorID != VID) && if ((VID != -1 && attr.VendorID != VID) &&
(PID != -1 && attr.ProductID != PID)) (PID != -1 && attr.ProductID != PID))
continue; /* This isn't it. */ continue; /* This isn't it. */
/* The VID and PID match. */ /* The VID and PID match. */
if(num-- == 0) if(num-- > 0)
return h; continue;
}
if(h != INVALID_HANDLE_VALUE)
CloseHandle (h);
return INVALID_HANDLE_VALUE; io.Open(path, blocksize);
return true;
} }
USBDevice::USBDevice() return false;
}
bool USBDevice::IsOpen() const
{ {
ZeroMemory( &ov, sizeof(ov) ); return io.IsOpen();
pending=false;
h = INVALID_HANDLE_VALUE;
} }
USBDevice::~USBDevice()
{
if(h != INVALID_HANDLE_VALUE)
CloseHandle(h);
}
bool USBDevice::Open(int VID, int PID, int num)
{
h = OpenUSB (VID, PID, num);
return h != INVALID_HANDLE_VALUE;
}
bool USBDevice::IsOpen()
{
return h != INVALID_HANDLE_VALUE;
}
int USBDevice::GetPadEvent() int USBDevice::GetPadEvent()
{ {
if(h == INVALID_HANDLE_VALUE) if(!IsOpen())
return -1; return -1;
int ret; long buf;
if( io.read(&buf) <= 0 )
return -1;
if(!pending) return buf;
}
WindowsFileIO::WindowsFileIO()
{
ZeroMemory( &ov, sizeof(ov) );
h = INVALID_HANDLE_VALUE;
buf = NULL;
}
WindowsFileIO::~WindowsFileIO()
{
if(h != INVALID_HANDLE_VALUE)
CloseHandle(h);
delete[] buf;
}
bool WindowsFileIO::Open(CString path, int blocksize_)
{
LOG->Trace( "WindowsFileIO::open(%s)", path.c_str() );
blocksize = blocksize_;
if(buf)
delete[] buf;
buf = new char[blocksize];
if(h != INVALID_HANDLE_VALUE)
CloseHandle (h);
h = CreateFile (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if(h == INVALID_HANDLE_VALUE)
return false;
queue_read();
return true;
}
void WindowsFileIO::queue_read()
{ {
/* Request feedback from the device. */ /* Request feedback from the device. */
unsigned long r; unsigned long r;
ret = ReadFile(h, &buf, sizeof(buf), &r, &ov); ReadFile(h, buf, blocksize, &r, &ov);
pending=true;
} }
int WindowsFileIO::finish_read(void *p)
{
LOG->Trace("this %p, %p", this, p);
/* We do; get the result. It'll go into the original buf
* we supplied on the original call; that's why buf is a
* member instead of a local. */
unsigned long cnt;
int ret = GetOverlappedResult(h, &ov, &cnt, FALSE);
if(ret == 0 && (GetLastError() == ERROR_IO_PENDING || GetLastError() == ERROR_IO_INCOMPLETE))
return -1;
queue_read();
if(ret == 0)
{
LOG->Warn(werr_ssprintf(GetLastError(), "Error reading Pump pad"));
return -1;
}
memcpy( p, buf, cnt );
return cnt;
}
int WindowsFileIO::read(void *p)
{
LOG->Trace( "WindowsFileIO::read()" );
/* See if we have a response for our request (which we may /* See if we have a response for our request (which we may
* have made on a previous call): */ * have made on a previous call): */
if(WaitForSingleObjectEx(h, 0, TRUE) == WAIT_TIMEOUT) if(WaitForSingleObjectEx(h, 0, TRUE) == WAIT_TIMEOUT)
return -1; return -1;
/* We do; get the result. It'll go into the original &buf return finish_read(p);
* we supplied on the original call; that's why buf is a }
* member instead of a local. */
unsigned long cnt;
ret = GetOverlappedResult(h, &ov, &cnt, FALSE);
pending=false;
if(ret == 0 && (GetLastError() == ERROR_IO_PENDING || GetLastError() == ERROR_IO_INCOMPLETE)) int WindowsFileIO::read_several(const vector<WindowsFileIO *> &sources, void *p, int &actual, float timeout)
return -1; {
HANDLE *Handles = new HANDLE[sources.size()];
for( unsigned i = 0; i < sources.size(); ++i )
Handles[i] = sources[i]->h;
if(ret == 0) { int ret = WaitForMultipleObjectsEx( sources.size(), Handles, false, int(timeout * 1000), true);
// this prints too much info in Win98 delete[] Handles;
// See if it's fixed--h should be INVALID_HANDLE_VALUE if
// the pad isn't there. -glenn if( ret == -1 )
LOG->Warn(werr_ssprintf(GetLastError(), "Error reading Pump pad")); {
LOG->Trace( werr_ssprintf(GetLastError(), "WaitForMultipleObjectsEx failed") );
return -1; return -1;
} }
return buf; if( ret >= int(WAIT_OBJECT_0) && ret < int(WAIT_OBJECT_0+sources.size()) )
{
actual = ret - WAIT_OBJECT_0;
return sources[actual]->finish_read(p);
}
return 0;
}
bool WindowsFileIO::IsOpen() const
{
return h != INVALID_HANDLE_VALUE;
} }
/* /*
+30 -8
View File
@@ -1,20 +1,42 @@
#ifndef WIN32_USB_H #ifndef WIN32_USB_H
#define WIN32_USB_H #define WIN32_USB_H
class USBDevice #include <vector>
/* The API for Windows device I/O is obscenely horrible, so encapsulate it. */
class WindowsFileIO
{ {
public: public:
USBDevice(); WindowsFileIO();
~USBDevice(); ~WindowsFileIO();
int GetPadEvent(); bool Open(CString path, int blocksize);
bool Open(int VID, int PID, int num); bool IsOpen() const;
bool IsOpen();
/* Returns the amount of data read. */
/* If nonblocking is true, this will */
/* Nonblocking read. size must always be the same. Returns the number of bytes
* read, or 0. */
int read(void *p);
static int read_several(const vector<WindowsFileIO *> &sources, void *p, int &actual, float timeout);
private: private:
HANDLE h; HANDLE h;
OVERLAPPED ov; OVERLAPPED ov;
long buf; char *buf;
bool pending; int blocksize;
void queue_read();
int finish_read(void *p);
};
class USBDevice
{
public:
int GetPadEvent();
bool Open(int VID, int PID, int blocksize, int num);
bool IsOpen() const;
WindowsFileIO io;
}; };
#endif #endif