OVR_Win32_HIDDevice.cpp
Go to the documentation of this file.
00001 /************************************************************************************
00002 
00003 Filename    :   OVR_Win32_HIDDevice.cpp
00004 Content     :   Win32 HID device implementation.
00005 Created     :   February 22, 2013
00006 Authors     :   Lee Cooper
00007 
00008 Copyright   :   Copyright 2013 Oculus VR, Inc. All Rights reserved.
00009 
00010 Use of this software is subject to the terms of the Oculus license
00011 agreement provided at the time of installation or download, or which
00012 otherwise accompanies this software in either electronic or hard copy form.
00013 
00014 *************************************************************************************/
00015 
00016 #include "OVR_Win32_HIDDevice.h"
00017 #include "OVR_Win32_DeviceManager.h"
00018 
00019 #include "Kernel/OVR_System.h"
00020 #include "Kernel/OVR_Log.h"
00021 
00022 namespace OVR { namespace Win32 {
00023 
00024 //-------------------------------------------------------------------------------------
00025 // HIDDevicePathWrapper is a simple class used to extract HID device file path
00026 // through SetupDiGetDeviceInterfaceDetail. We use a class since this is a bit messy.
00027 class HIDDevicePathWrapper
00028 {
00029     SP_INTERFACE_DEVICE_DETAIL_DATA_A* pData;
00030 public:
00031     HIDDevicePathWrapper() : pData(0) { }
00032     ~HIDDevicePathWrapper() { if (pData) OVR_FREE(pData); }
00033 
00034     const char* GetPath() const { return pData ? pData->DevicePath : 0; }
00035 
00036     bool InitPathFromInterfaceData(HDEVINFO hdevInfoSet, SP_DEVICE_INTERFACE_DATA* pidata);
00037 };
00038 
00039 bool HIDDevicePathWrapper::InitPathFromInterfaceData(HDEVINFO hdevInfoSet, SP_DEVICE_INTERFACE_DATA* pidata)
00040 {
00041     DWORD detailSize = 0;
00042     // SetupDiGetDeviceInterfaceDetailA returns "not enough buffer error code"
00043     // doe size request. Just check valid size.
00044     SetupDiGetDeviceInterfaceDetailA(hdevInfoSet, pidata, NULL, 0, &detailSize, NULL);
00045     if (!detailSize ||
00046         ((pData = (SP_INTERFACE_DEVICE_DETAIL_DATA_A*)OVR_ALLOC(detailSize)) == 0))
00047         return false;
00048     pData->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA_A);
00049 
00050     if (!SetupDiGetDeviceInterfaceDetailA(hdevInfoSet, pidata, pData, detailSize, NULL, NULL))
00051         return false;
00052     return true;
00053 }
00054 
00055 
00056 //-------------------------------------------------------------------------------------
00057 // **** Win32::DeviceManager
00058 
00059 HIDDeviceManager::HIDDeviceManager(DeviceManager* manager)
00060  :  Manager(manager)
00061 {
00062     hHidLib = ::LoadLibraryA("hid.dll");
00063     OVR_ASSERT_LOG(hHidLib, ("Couldn't load Win32 'hid.dll'."));
00064 
00065     OVR_RESOLVE_HIDFUNC(HidD_GetHidGuid);
00066     OVR_RESOLVE_HIDFUNC(HidD_SetNumInputBuffers);
00067     OVR_RESOLVE_HIDFUNC(HidD_GetFeature);
00068     OVR_RESOLVE_HIDFUNC(HidD_SetFeature);
00069     OVR_RESOLVE_HIDFUNC(HidD_GetAttributes);
00070     OVR_RESOLVE_HIDFUNC(HidD_GetManufacturerString);
00071     OVR_RESOLVE_HIDFUNC(HidD_GetProductString);
00072     OVR_RESOLVE_HIDFUNC(HidD_GetSerialNumberString);
00073     OVR_RESOLVE_HIDFUNC(HidD_GetPreparsedData);   
00074     OVR_RESOLVE_HIDFUNC(HidD_FreePreparsedData);  
00075     OVR_RESOLVE_HIDFUNC(HidP_GetCaps);    
00076 
00077     if (HidD_GetHidGuid)
00078         HidD_GetHidGuid(&HidGuid);
00079 }
00080 
00081 HIDDeviceManager::~HIDDeviceManager()
00082 {
00083     ::FreeLibrary(hHidLib);
00084 }
00085 
00086 bool HIDDeviceManager::Initialize()
00087 {
00088     return true;
00089 }
00090 
00091 void HIDDeviceManager::Shutdown()
00092 {   
00093     LogText("OVR::Win32::HIDDeviceManager - shutting down.\n");
00094 }
00095 
00096 bool HIDDeviceManager::Enumerate(HIDEnumerateVisitor* enumVisitor)
00097 {
00098     HDEVINFO                 hdevInfoSet;
00099     SP_DEVICE_INTERFACE_DATA interfaceData;
00100     interfaceData.cbSize = sizeof(interfaceData);
00101 
00102     // Get handle to info data set describing all available HIDs.
00103     hdevInfoSet = SetupDiGetClassDevsA(&HidGuid, NULL, NULL, DIGCF_INTERFACEDEVICE | DIGCF_PRESENT);
00104     if (hdevInfoSet == INVALID_HANDLE_VALUE)
00105         return false;
00106 
00107     for(int deviceIndex = 0;
00108         SetupDiEnumDeviceInterfaces(hdevInfoSet, NULL, &HidGuid, deviceIndex, &interfaceData);
00109         deviceIndex++)
00110     {
00111         // For each device, we extract its file path and open it to get attributes,
00112         // such as vendor and product id. If anything goes wrong, we move onto next device.
00113         HIDDevicePathWrapper pathWrapper;
00114         if (!pathWrapper.InitPathFromInterfaceData(hdevInfoSet, &interfaceData))
00115             continue;
00116 
00117         // Look for the device to check if it is already opened.
00118         Ptr<DeviceCreateDesc> existingDevice = Manager->FindDevice(pathWrapper.GetPath());
00119         // if device exists and it is opened then most likely the CreateHIDFile
00120         // will fail; therefore, we just set Enumerated to 'true' and continue.
00121         if (existingDevice && existingDevice->pDevice)
00122         {
00123             existingDevice->Enumerated = true;
00124             continue;
00125         }
00126 
00127         // open device in non-exclusive mode for detection...
00128         HANDLE hidDev = CreateHIDFile(pathWrapper.GetPath(), false);
00129         if (hidDev == INVALID_HANDLE_VALUE)
00130             continue;
00131 
00132         HIDDeviceDesc devDesc;
00133         devDesc.Path = pathWrapper.GetPath();
00134         if (initVendorProductVersion(hidDev, &devDesc) &&
00135             enumVisitor->MatchVendorProduct(devDesc.VendorId, devDesc.ProductId) &&
00136             initUsage(hidDev, &devDesc))
00137         {
00138             initStrings(hidDev, &devDesc);
00139 
00140             // Construct minimal device that the visitor callback can get feature reports from.
00141             Win32::HIDDevice device(this, hidDev);
00142             enumVisitor->Visit(device, devDesc);
00143         }
00144 
00145         ::CloseHandle(hidDev);
00146     }
00147 
00148     SetupDiDestroyDeviceInfoList(hdevInfoSet);
00149     return true;
00150 }
00151 
00152 bool HIDDeviceManager::GetHIDDeviceDesc(const String& path, HIDDeviceDesc* pdevDesc) const
00153 {
00154     // open device in non-exclusive mode for detection...
00155     HANDLE hidDev = CreateHIDFile(path, false);
00156     if (hidDev == INVALID_HANDLE_VALUE)
00157         return false;
00158 
00159     pdevDesc->Path = path;
00160     getFullDesc(hidDev, pdevDesc);
00161 
00162     ::CloseHandle(hidDev);
00163     return true;
00164 }
00165 
00166 OVR::HIDDevice* HIDDeviceManager::Open(const String& path)
00167 {
00168 
00169     Ptr<Win32::HIDDevice> device = *new Win32::HIDDevice(this);
00170 
00171     if (device->HIDInitialize(path))
00172     {
00173         device->AddRef();        
00174         return device;
00175     }
00176 
00177     return NULL;
00178 }
00179 
00180 bool HIDDeviceManager::getFullDesc(HANDLE hidDev, HIDDeviceDesc* desc) const
00181 {
00182 
00183     if (!initVendorProductVersion(hidDev, desc))
00184     {
00185         return false;
00186     }
00187 
00188     if (!initUsage(hidDev, desc))
00189     {
00190         return false;
00191     }
00192 
00193     initStrings(hidDev, desc);
00194 
00195     return true;
00196 }
00197 
00198 bool HIDDeviceManager::initVendorProductVersion(HANDLE hidDev, HIDDeviceDesc* desc) const
00199 {
00200     HIDD_ATTRIBUTES attr;
00201     attr.Size = sizeof(attr);
00202     if (!HidD_GetAttributes(hidDev, &attr))
00203         return false;
00204     desc->VendorId      = attr.VendorID;
00205     desc->ProductId     = attr.ProductID;
00206     desc->VersionNumber = attr.VersionNumber;
00207     return true;
00208 }
00209 
00210 bool HIDDeviceManager::initUsage(HANDLE hidDev, HIDDeviceDesc* desc) const
00211 {
00212     bool                 result = false;
00213     HIDP_CAPS            caps;
00214     HIDP_PREPARSED_DATA* preparsedData = 0;
00215 
00216     if (!HidD_GetPreparsedData(hidDev, &preparsedData))
00217         return false;
00218 
00219     if (HidP_GetCaps(preparsedData, &caps) == HIDP_STATUS_SUCCESS)
00220     {
00221         desc->Usage                  = caps.Usage;
00222         desc->UsagePage              = caps.UsagePage;
00223         result = true;
00224     }
00225     HidD_FreePreparsedData(preparsedData);
00226     return result;
00227 }
00228 
00229 void HIDDeviceManager::initStrings(HANDLE hidDev, HIDDeviceDesc* desc) const
00230 {
00231     // Documentation mentions 126 as being the max for USB.
00232     wchar_t strBuffer[196];
00233 
00234     // HidD_Get*String functions return nothing in buffer on failure,
00235     // so it's ok to do this without further error checking.
00236     strBuffer[0] = 0;
00237     HidD_GetManufacturerString(hidDev, strBuffer, sizeof(strBuffer));
00238     desc->Manufacturer = strBuffer;
00239 
00240     strBuffer[0] = 0;
00241     HidD_GetProductString(hidDev, strBuffer, sizeof(strBuffer));
00242     desc->Product = strBuffer;
00243 
00244     strBuffer[0] = 0;
00245     HidD_GetSerialNumberString(hidDev, strBuffer, sizeof(strBuffer));
00246     desc->SerialNumber = strBuffer;
00247 }
00248 
00249 //-------------------------------------------------------------------------------------
00250 // **** Win32::HIDDevice
00251 
00252 HIDDevice::HIDDevice(HIDDeviceManager* manager)
00253  : HIDManager(manager), inMinimalMode(false), Device(0), ReadRequested(false)
00254 {
00255     memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
00256 }
00257 
00258 // This is a minimal constructor used during enumeration for us to pass
00259 // a HIDDevice to the visit function (so that it can query feature reports). 
00260 HIDDevice::HIDDevice(HIDDeviceManager* manager, HANDLE device)
00261  : HIDManager(manager), inMinimalMode(true), Device(device), ReadRequested(true)
00262 {
00263     memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
00264 }
00265 
00266 HIDDevice::~HIDDevice()
00267 {
00268     if (!inMinimalMode)
00269     {
00270         HIDShutdown();
00271     }
00272 }
00273 
00274 bool HIDDevice::HIDInitialize(const String& path)
00275 {
00276 
00277     DevDesc.Path = path;
00278 
00279     if (!openDevice())
00280     {
00281         LogText("OVR::Win32::HIDDevice - Failed to open HIDDevice: ", path);
00282         return false;
00283     }
00284 
00285 
00286     HIDManager->Manager->pThread->AddTicksNotifier(this);
00287     HIDManager->Manager->pThread->AddMessageNotifier(this);
00288 
00289     LogText("OVR::Win32::HIDDevice - Opened '%s'\n"
00290         "                    Manufacturer:'%s'  Product:'%s'  Serial#:'%s'\n",
00291         DevDesc.Path.ToCStr(),
00292         DevDesc.Manufacturer.ToCStr(), DevDesc.Product.ToCStr(),
00293         DevDesc.SerialNumber.ToCStr());
00294 
00295     return true;
00296 }
00297 
00298 bool HIDDevice::initInfo()
00299 {
00300     // Device must have been successfully opened.
00301     OVR_ASSERT(Device);
00302 
00303     // Get report lengths.
00304     HIDP_PREPARSED_DATA* preparsedData = 0;
00305     if (!HIDManager->HidD_GetPreparsedData(Device, &preparsedData))
00306     {
00307         return false;
00308     }
00309 
00310     HIDP_CAPS caps;
00311     if (HIDManager->HidP_GetCaps(preparsedData, &caps) != HIDP_STATUS_SUCCESS)
00312     {
00313         HIDManager->HidD_FreePreparsedData(preparsedData);
00314         return false;
00315     }
00316 
00317     InputReportBufferLength  = caps.InputReportByteLength;
00318     OutputReportBufferLength = caps.OutputReportByteLength;
00319     FeatureReportBufferLength= caps.FeatureReportByteLength;
00320     HIDManager->HidD_FreePreparsedData(preparsedData);
00321 
00322     if (ReadBufferSize < InputReportBufferLength)
00323     {
00324         OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer."));
00325         return false;
00326     }
00327 
00328     // Get device desc.
00329     if (!HIDManager->getFullDesc(Device, &DevDesc))
00330     {
00331         OVR_ASSERT_LOG(false, ("Failed to get device desc while initializing device."));
00332         return false;
00333     }
00334 
00335     return true;
00336 }
00337 
00338 bool HIDDevice::openDevice()
00339 {
00340     memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
00341 
00342     Device = HIDManager->CreateHIDFile(DevDesc.Path.ToCStr());
00343     if (Device == INVALID_HANDLE_VALUE)
00344     {
00345         OVR_DEBUG_LOG(("Failed 'CreateHIDFile' while opening device, error = 0x%X.", 
00346                         ::GetLastError()));
00347         Device = 0;
00348         return false;
00349     }
00350 
00351     if (!HIDManager->HidD_SetNumInputBuffers(Device, 128))
00352     {
00353         OVR_ASSERT_LOG(false, ("Failed 'HidD_SetNumInputBuffers' while initializing device."));
00354         ::CloseHandle(Device);
00355         Device = 0;
00356         return false;
00357     }
00358 
00359 
00360     // Create a manual-reset non-signaled event.
00361     ReadOverlapped.hEvent = ::CreateEvent(0, TRUE, FALSE, 0);
00362 
00363     if (!ReadOverlapped.hEvent)
00364     {
00365         OVR_ASSERT_LOG(false, ("Failed to create event."));
00366         ::CloseHandle(Device);
00367         Device = 0;
00368         return false;
00369     }
00370 
00371     if (!initInfo())
00372     {
00373         OVR_ASSERT_LOG(false, ("Failed to get HIDDevice info."));
00374 
00375         ::CloseHandle(ReadOverlapped.hEvent);
00376         memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
00377 
00378         ::CloseHandle(Device);
00379         Device = 0;
00380         return false;
00381     }
00382 
00383     if (!initializeRead())
00384     {
00385         OVR_ASSERT_LOG(false, ("Failed to get intialize read for HIDDevice."));
00386 
00387         ::CloseHandle(ReadOverlapped.hEvent);
00388         memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
00389 
00390         ::CloseHandle(Device);
00391         Device = 0;
00392         return false;
00393     }
00394 
00395     return true;
00396 }
00397 
00398 void HIDDevice::HIDShutdown()
00399 {   
00400 
00401     HIDManager->Manager->pThread->RemoveTicksNotifier(this);
00402     HIDManager->Manager->pThread->RemoveMessageNotifier(this);
00403 
00404     closeDevice();
00405     LogText("OVR::Win32::HIDDevice - Closed '%s'\n", DevDesc.Path.ToCStr());
00406 }
00407 
00408 bool HIDDevice::initializeRead()
00409 {
00410 
00411     if (!ReadRequested)
00412     {        
00413         HIDManager->Manager->pThread->AddOverlappedEvent(this, ReadOverlapped.hEvent);
00414         ReadRequested = true;
00415     }
00416 
00417     // Read resets the event...
00418     while(::ReadFile(Device, ReadBuffer, InputReportBufferLength, 0, &ReadOverlapped))
00419     {
00420         processReadResult();
00421     }
00422 
00423     if (GetLastError() != ERROR_IO_PENDING)
00424     {
00425         // Some other error (such as unplugged).
00426         closeDeviceOnIOError();
00427         return false;
00428     }
00429 
00430     return true;
00431 }
00432 
00433 bool HIDDevice::processReadResult()
00434 {
00435 
00436     OVR_ASSERT(ReadRequested);
00437 
00438     DWORD bytesRead = 0;
00439 
00440     if (GetOverlappedResult(Device, &ReadOverlapped, &bytesRead, FALSE))
00441     {
00442         // We've got data.
00443         if (Handler)
00444         {
00445             Handler->OnInputReport(ReadBuffer, bytesRead);
00446         }
00447 
00448         // TBD: Not needed?
00449         // Event should be reset by Read call...
00450         ReadOverlapped.Pointer = 0;
00451         ReadOverlapped.Internal = 0;
00452         ReadOverlapped.InternalHigh = 0;
00453         return true;
00454     }
00455     else
00456     {
00457         if (GetLastError() != ERROR_IO_PENDING)
00458         {
00459             closeDeviceOnIOError();
00460             return false;
00461         }
00462     }
00463 
00464     return false;
00465 }
00466 
00467 void HIDDevice::closeDevice()
00468 {
00469     if (ReadRequested)
00470     {
00471         HIDManager->Manager->pThread->RemoveOverlappedEvent(this, ReadOverlapped.hEvent);
00472         ReadRequested = false;
00473         // Must call this to avoid Win32 assertion; CloseHandle is not enough.
00474         ::CancelIo(Device);
00475     }
00476 
00477     ::CloseHandle(ReadOverlapped.hEvent);
00478     memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
00479 
00480     ::CloseHandle(Device);
00481     Device = 0;
00482 }
00483 
00484 void HIDDevice::closeDeviceOnIOError()
00485 {
00486     LogText("OVR::Win32::HIDDevice - Lost connection to '%s'\n", DevDesc.Path.ToCStr());
00487     closeDevice();
00488 }
00489 
00490 bool HIDDevice::SetFeatureReport(UByte* data, UInt32 length)
00491 {
00492     if (!ReadRequested)
00493         return false;
00494 
00495     return HIDManager->HidD_SetFeature(Device, data, (ULONG) length) != FALSE;
00496 }
00497 
00498 bool HIDDevice::GetFeatureReport(UByte* data, UInt32 length)
00499 {
00500     if (!ReadRequested)
00501         return false;
00502 
00503         return HIDManager->HidD_GetFeature(Device, data, (ULONG) length) != FALSE;
00504 }
00505 
00506 void HIDDevice::OnOverlappedEvent(HANDLE hevent)
00507 {
00508     OVR_UNUSED(hevent);
00509     OVR_ASSERT(hevent == ReadOverlapped.hEvent);
00510 
00511     if (processReadResult()) 
00512     {
00513         // Proceed to read again.
00514         initializeRead();
00515     }
00516 }
00517 
00518 UInt64 HIDDevice::OnTicks(UInt64 ticksMks)
00519 {
00520     if (Handler)
00521     {
00522         return Handler->OnTicks(ticksMks);
00523     }
00524 
00525     return DeviceManagerThread::Notifier::OnTicks(ticksMks);
00526 }
00527 
00528 bool HIDDevice::OnDeviceMessage(DeviceMessageType messageType, 
00529                                                                 const String& devicePath,
00530                                                                 bool* error)
00531 {
00532 
00533     // Is this the correct device?
00534     if (DevDesc.Path.CompareNoCase(devicePath) != 0)
00535     {
00536         return false;
00537     }
00538 
00539     if (messageType == DeviceMessage_DeviceAdded && !Device)
00540     {
00541         // A closed device has been re-added. Try to reopen.
00542         if (!openDevice())
00543         {
00544             LogError("OVR::Win32::HIDDevice - Failed to reopen a device '%s' that was re-added.\n", devicePath.ToCStr());
00545                         *error = true;
00546             return true;
00547         }
00548 
00549         LogText("OVR::Win32::HIDDevice - Reopened device '%s'\n", devicePath.ToCStr());
00550     }
00551 
00552     HIDHandler::HIDDeviceMessageType handlerMessageType = HIDHandler::HIDDeviceMessage_DeviceAdded;
00553     if (messageType == DeviceMessage_DeviceAdded)
00554     {
00555     }
00556     else if (messageType == DeviceMessage_DeviceRemoved)
00557     {
00558         handlerMessageType = HIDHandler::HIDDeviceMessage_DeviceRemoved;
00559     }
00560     else
00561     {
00562         OVR_ASSERT(0);          
00563     }
00564 
00565     if (Handler)
00566     {
00567         Handler->OnDeviceMessage(handlerMessageType);
00568     }
00569 
00570         *error = false;
00571     return true;
00572 }
00573 
00574 HIDDeviceManager* HIDDeviceManager::CreateInternal(Win32::DeviceManager* devManager)
00575 {
00576 
00577     if (!System::IsInitialized())
00578     {
00579         // Use custom message, since Log is not yet installed.
00580         OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
00581             LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
00582         return 0;
00583     }
00584 
00585     Ptr<Win32::HIDDeviceManager> manager = *new Win32::HIDDeviceManager(devManager);
00586 
00587     if (manager)
00588     {
00589         if (manager->Initialize())
00590         {
00591             manager->AddRef();
00592         }
00593         else
00594         {
00595             manager.Clear();
00596         }
00597     }
00598 
00599     return manager.GetPtr();
00600 }
00601 
00602 } // namespace Win32
00603 
00604 //-------------------------------------------------------------------------------------
00605 // ***** Creation
00606 
00607 // Creates a new HIDDeviceManager and initializes OVR.
00608 HIDDeviceManager* HIDDeviceManager::Create()
00609 {
00610     OVR_ASSERT_LOG(false, ("Standalone mode not implemented yet."));
00611 
00612     if (!System::IsInitialized())
00613     {
00614         // Use custom message, since Log is not yet installed.
00615         OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
00616             LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
00617         return 0;
00618     }
00619 
00620     Ptr<Win32::HIDDeviceManager> manager = *new Win32::HIDDeviceManager(NULL);
00621 
00622     if (manager)
00623     {
00624         if (manager->Initialize())
00625         {
00626             manager->AddRef();
00627         }
00628         else
00629         {
00630             manager.Clear();
00631         }
00632     }
00633 
00634     return manager.GetPtr();
00635 }
00636 
00637 } // namespace OVR


oculus_sdk
Author(s):
autogenerated on Mon Oct 6 2014 03:01:19