From 5c1329067cc68f73346941c90e53f871f3e056b2 Mon Sep 17 00:00:00 2001 From: Mark Cannon Date: Sun, 29 Aug 2010 05:04:42 +0000 Subject: [PATCH] Committed partially done generic USB driver for WinUSB/libusb git-svn-id: https://openitg.svn.sourceforge.net/svnroot/openitg/branches/dev@802 83fadc84-e282-4d84-a09a-c4228d6ae7e5 --- src/arch/USB/USBDriver_Impl.h | 29 +++++++ src/arch/USB/USBDriver_Impl_Libusb.cpp | 149 ++++++++++++++++++++++++++++++++ src/arch/USB/USBDriver_Impl_Libusb.h | 35 ++++++++ src/arch/USB/USBDriver_Impl_WinUSB.cpp | 150 +++++++++++++++++++++++++++++++++ src/arch/USB/USBDriver_Impl_WinUSB.h | 34 ++++++++ 5 files changed, 397 insertions(+) create mode 100644 src/arch/USB/USBDriver_Impl.h create mode 100644 src/arch/USB/USBDriver_Impl_Libusb.cpp create mode 100644 src/arch/USB/USBDriver_Impl_Libusb.h create mode 100644 src/arch/USB/USBDriver_Impl_WinUSB.cpp create mode 100644 src/arch/USB/USBDriver_Impl_WinUSB.h diff --git a/src/arch/USB/USBDriver_Impl.h b/src/arch/USB/USBDriver_Impl.h new file mode 100644 index 00000000..cb9ffc4c --- /dev/null +++ b/src/arch/USB/USBDriver_Impl.h @@ -0,0 +1,29 @@ +#ifndef USB_DRIVER_IMPL_H +#define USB_DRIVER_IMPL_H + +class USBDriver_Impl +{ +public: + USBDriver_Impl(); + virtual ~USBDriver_Impl(); + + virtual bool Open( int iVendorID, int iProductID ) = 0; + virtual void Close(); + + virtual int ControlMessage( int iType, int iRequest, int iValue, int iIndex, char *pData, int iSize, int iTimeout ) = 0; + + virtual int BulkRead( int iEndpoint, char *pData, int iSize, int iTimeout ) = 0; + virtual int BulkWrite( int iEndpoint, char *pData, int iSize, int iTimeout ) = 0; + + virtual int InterruptRead( int iEndpoint, char *pData, int iSize, int iTimeout ) = 0; + virtual int InterruptWrite( int iEndpoint, char *pData, int iSize, int iTimeout ) = 0; + +protected: + virtual bool SetConfiguration( int iConfig ) = 0; + + virtual bool ClaimInterface( int iInterface ) = 0; + virtual bool ReleaseInterface( int iInterface ) = 0; +}; + +#endif // USB_DRIVER_H + diff --git a/src/arch/USB/USBDriver_Impl_Libusb.cpp b/src/arch/USB/USBDriver_Impl_Libusb.cpp new file mode 100644 index 00000000..5c0deeb4 --- /dev/null +++ b/src/arch/USB/USBDriver_Impl_Libusb.cpp @@ -0,0 +1,149 @@ +#include "global.h" +#include "RageLog.h" +#include "USBDriver_Impl_Libusb.h" + +USBDriver_Impl_Libusb::USBDriver_Impl_Libusb() +{ + usb_init(); + m_pHandle = NULL; +} + +static struct usb_device *FindDevice( int iVendorID, int iProductID ) +{ + for( usb_bus *bus = usb_get_busses(); bus; bus = bus->next ) + for( struct usb_device *dev = bus->devices; dev; dev = dev->next ) + if( iVendorID == dev->descriptor.idVendor && iProductID == dev->descriptor.idProduct ) + return dev; + + // fall through + LOG->Trace( "FindDevice() found no matches." ); + return NULL; +} + + +bool USBDriver_Impl_Libusb::Open( int iVendorID, int iProductID ) +{ + Close(); + + if( usb_find_busses() < 0 ) + { + LOG->Warn( "Libusb: usb_find_busses: %s", usb_strerror() ); + return false; + } + + if( usb_find_devices() < 0 ) + { + LOG->Warn( "Libusb: usb_find_devices: %s", usb_strerror() ); + return false; + } + + struct usb_device *dev = FindDevice( iVendorID, iProductID ); + + if( dev == NULL ) + { + LOG->Warn( "Libusb: no match for %04x, %04x.", iVendorID, iProductID ); + return false; + } + + m_pHandle = usb_open( dev ); + + if( m_pHandle == NULL ) + { + LOG->Warn( "Libusb: usb_open: %s", usb_strerror() ); + return false; + } + +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP + // The device may be claimed by a kernel driver. Attempt to reclaim it. + for( unsigned i = 0; i < dev->config->bNumInterfaces; i++ ) + { + int iResult = usb_detach_kernel_driver_np( m_pHandle, i ); + + switch( iResult ) + { + case -61: // "No data available" (no driver attached) - continue + case 0: // no error + continue; + break; + default: // unhandled error + LOG->Warn( "Libusb: usb_detach_kernel_driver_np: %s", usb_strerror() ); + Close(); + return false; + break; + } + } + +#endif + + if ( !SetConfiguration(dev->config->bConfigurationValue) ) + { + LOG->Warn( "Libusb: usb_set_configuration: %s", usb_strerror() ); + Close(); + return false; + } + + // attempt to claim all interfaces for this device + for( unsigned i = 0; i < dev->config->bNumInterfaces; i++ ) + { + if ( !ClaimInterface(i) ) + { + LOG->Warn( "Libusb: usb_claim_interface(%i): %s", i, usb_strerror() ); + Close(); + return false; + } + } + + return true; +} + +void USBDriver_Impl_Libusb::Close() +{ + // never opened + if( m_pHandle == NULL ) + return; + + usb_set_altinterface( m_pHandle, 0 ); + usb_reset( m_pHandle ); + usb_close( m_pHandle ); + m_pHandle = NULL; +} + +int USBDriver_Impl_Libusb::ControlMessage( int iType, int iRequest, int iValue, int iIndex, char *pData, int iSize, int iTimeout ) +{ + return usb_control_msg( m_pHandle, iType, iRequest, iValue, iIndex, pData, iSize, iTimeout ); +} + +int USBDriver_Impl_Libusb::BulkRead( int iEndpoint, char *pData, int iSize, int iTimeout ) +{ + return usb_bulk_read( m_pHandle, iEndpoint, pData, iSize, iTimeout ); +} + +int USBDriver_Impl_Libusb::BulkWrite( int iEndpoint, char *pData, int iSize, int iTimeout ) +{ + return usb_bulk_write( m_pHandle, iEndpoint, pData, iSize, iTimeout ); +} + +int USBDriver_Impl_Libusb::InterruptRead( int iEndpoint, char *pData, int iSize, int iTimeout ) +{ + return usb_interrupt_read( m_pHandle, iEndpoint, pData, iSize, iTimeout ); +} + +int USBDriver_Impl_Libusb::InterruptWrite( int iEndpoint,char *pData, int iSize, int iTimeout ) +{ + return usb_interrupt_write( m_pHandle, iEndpoint, pData, iSize, iTimeout ); +} + +bool USBDriver_Impl_Libusb::SetConfiguration( int iConfig ) +{ + return usb_set_configuration( m_pHandle, iConfig ) == 0; +} + +bool USBDriver_Impl_Libusb::ClaimInterface( int iInterface ) +{ + return usb_claim_interface( m_pHandle, iInterface ) == 0; +} + +bool USBDriver_Impl_Libusb::ReleaseInterface( int iInterface ) +{ + return usb_release_interface( m_pHandle, iInterface ) == 0; +} diff --git a/src/arch/USB/USBDriver_Impl_Libusb.h b/src/arch/USB/USBDriver_Impl_Libusb.h new file mode 100644 index 00000000..b541b86e --- /dev/null +++ b/src/arch/USB/USBDriver_Impl_Libusb.h @@ -0,0 +1,35 @@ +#ifndef USB_DRIVER_IMPL_LIBUSB_H +#define USB_DRIVER_IMPL_LIBUSB_H + +#include "USBDriver_Impl.h" +#include + +class USBDriver_Impl_Libusb : public USBDriver_Impl +{ +public: + USBDriver_Impl_Libusb(); + ~USBDriver_Impl_Libusb(); + + bool Open( int iVendorID, int iProductID ); + void Close(); + + int ControlMessage( int iType, int iRequest, int iValue, int iIndex, char *pData, int iSize, int iTimeout ); + + int BulkRead( int iEndpoint, char *pData, int iSize, int iTimeout ); + int BulkWrite( int iEndpoint, char *pData, int iSize, int iTimeout ); + + int InterruptRead( int iEndpoint, char *pData, int iSize, int iTimeout ); + int InterruptWrite( int iEndpoint, char *pData, int iSize, int iTimeout ); + +protected: + bool SetConfiguration( int iConfig ); + + bool ClaimInterface( int iInterface ); + bool ReleaseInterface( int iInterface ); + +private: + usb_dev_handle *m_pHandle; +}; + +#endif // USB_DRIVER_LIBUSB_H + diff --git a/src/arch/USB/USBDriver_Impl_WinUSB.cpp b/src/arch/USB/USBDriver_Impl_WinUSB.cpp new file mode 100644 index 00000000..daab070a --- /dev/null +++ b/src/arch/USB/USBDriver_Impl_WinUSB.cpp @@ -0,0 +1,150 @@ +#include "global.h" +#include "RageLog.h" +#include "RageUtil.h" +#include "USBDriver_Impl_WinUSB.h" + +#include +#include + +#pragma comment (lib, "setupapi.lib" ) +#pragma comment (lib, "winusb.lib" ) + +USBDriver_Impl_WinUSB::USBDriver_Impl_WinUSB() +{ + m_hDevice = INVALID_HANDLE_VALUE; +} + +USBDriver_Impl_WinUSB::~USBDriver_Impl_WinUSB() +{ +} + +/* There are not words for how much I hate Microsoft APIs. -- vyhd */ +bool USBDriver_Impl_WinUSB::Open( int iVendorID, int iProductID ) +{ + // get a set of all the devices currently on the system + HDEVINFO hDeviceInfo = SetupDiGetClassDevs( NULL, NULL, NULL, DIGCF_PRESENT ); + + if( hDeviceInfo == INVALID_HANDLE_VALUE ) + { + LOG->Trace( "WinUSB: SetupDiGetClassDevs failed (error %i)", GetLastError() ); + return false; + } + + SP_DEVINFO_DATA DeviceInfoData; + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + PSP_DEVICE_INTERFACE_DATA pInterfaceDetailData = NULL; + + LPTSTR lpDevicePath = NULL; + + for( int i = 0; SetupDiEnumDeviceInfo(hDeviceInfo, i, &DeviceInfoData); ++i ) + { + if( lpDevicePath ) + LocalFree( lpDevicePath ); + if( pDeviceInterfaceData ) + LocalFree( pDeviceInterfaceData ); + + DeviceInterfaceData.czSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + bool bSuccess = SetupDiEnumDeviceInterfaces( hDeviceInfo, &DeviceInfoData, NULL, i, &DeviceInterfaceData ); + + if( GetLastError() == ERROR_NO_MORE_ITEMS ) + break; + + if( !bSuccess ) + { + LOG->Warn( "SetupDiEnumDeviceInterfaces failed with %d", GetLastError() ); + break; + } + + int iRequiredLength = -1; + + bResult = SetupDiGetDeviceInterfaceDetail( hDeviceInfo, &DeviceInterfaceData, NULL, 0, &iRequiredLength, NULL ); + + if( !bResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER ) + { + pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, iRequiredLength); + + if( !pInterfaceDetailData ) + { + LOG->Warn( "Error allocating pInterfaceDetailData." ); + break; + } + } + + if( pInterfaceDetailSize ) + pInterfaceDetailSize->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + else + LOG->Warn( "XXX pInterfaceDetailSize is NULL, assumed not NULL" ); + + bResult = SetupDiGetDeviceInterfaceDetail( hDeviceInfo, &DeviceInterfaceData, pInterfaceDetailData, iRequiredLength, NULL, &DeviceInfoData ); + + if( !bResult ) + { + LOG->Warn( "SetupDiGetDeviceInterfaceDetai: %d", GetLastError() ); + break; + } + + + return SetupDiDestroyDeviceInfoList( hDeviceInfo ); +} + +void USBDriver_Impl_WinUSB::Close() +{ +} + +int USBDriver_Impl_WinUSB::ControlMessage( int iType, int iRequest, int iValue, int iIndex, char *pData, int iSize, int iTimeout ) +{ + // TODO: use WinUsb_SetPipePolicy to set timeout? + WINUSB_SETUP_PACKET msg; + msg.RequestType = iType; + msg.Request = iRequest; + msg.Value = iValue; + msg.Index = iIndex; + msg.Length = iSize; + + int iRet = -1; + + // TODO: are we sure that iRet will stay -1 when the call fails? + WinUsb_ControlTransfer( m_pDevice, &msg, pData, iSize, &iRet ); + return iRet; +} + +int USBDriver_Impl_WinUSB::BulkRead( int iEndpoint, char *pData, int iSize, int iTimeout ) +{ + int iRet = -1; + WinUsb_ReadPipe( m_hDevice, iEndpoint, pData, iSize ); + return iRet; +} + +int USBDriver_Impl_WinUSB::BulkWrite( int iEndpoint, char *pData, int iSize, int iTimeout ) +{ + int iRet = -1; + WinUsb_WritePipe( m_hDevice, iEndpoint, pData, iSize ); + return iRet; +} + +int USBDriver_Impl_WinUSB::InterruptRead( int iEndpoint, char *pData, int iSize, int iTimeout ) +{ + return 0; +} + +int USBDriver_Impl_WinUSB::InterruptWrite( int iEndpoint, char *pData, int iSize, int iTimeout ) +{ + return 0; +} + +bool USBDriver_Impl_WinUSB::SetConfiguration( int iConfig ) +{ + return false; +} + +bool USBDriver_Impl_WinUSB::ClaimInterface( int iInterface ) +{ + return false; +} + +bool USBDriver_Impl_WinUSB::ReleaseInterface( int iInterface ) +{ + return false; +} + diff --git a/src/arch/USB/USBDriver_Impl_WinUSB.h b/src/arch/USB/USBDriver_Impl_WinUSB.h new file mode 100644 index 00000000..a21dba21 --- /dev/null +++ b/src/arch/USB/USBDriver_Impl_WinUSB.h @@ -0,0 +1,34 @@ +#ifndef USB_DRIVER_IMPL_WINUSB_H +#define USB_DRIVER_IMPL_WINUSB_H + +#include "USBDriver_Impl.h" +#include + +class USBDriver_Impl_WinUSB : public USBDriver_Impl +{ +public: + USBDriver_Impl(); + ~USBDriver_Impl(); + + bool Open( int iVendorID, int iProductID ); + void Close(); + + int ControlMessage( int iType, int iRequest, int iValue, int iIndex, char *pData, int iSize, int iTimeout ); + + int BulkRead( int iEndpoint, char *pData, int iSize, int iTimeout ); + int BulkWrite( int iEndpoint, char *pData, int iSize, int iTimeout ); + + int InterruptRead( int iEndpoint, char *pData, int iSize, int iTimeout ); + int InterruptWrite( int iEndpoint, char *pData, int iSize, int iTimeout ); + +protected: + bool SetConfiguration( int iConfig ); + + bool ClaimInterface( int iInterface ); + bool ReleaseInterface( int iInterface ); + +private: + WINUSB_INTERFACE_HANDLE m_hDevice; +}; + +#endif // USBDRIVER_IMPL_WINUSB_H -- 2.11.0