oculus1
view libovr/Src/win32/OVR_Win32_HIDDevice.cpp @ 1:e2f9e4603129
added LibOVR and started a simple vr wrapper.
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 14 Sep 2013 16:14:59 +0300 |
parents | |
children |
line source
1 /************************************************************************************
3 Filename : OVR_Win32_HIDDevice.cpp
4 Content : Win32 HID device implementation.
5 Created : February 22, 2013
6 Authors : Lee Cooper
8 Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
10 Use of this software is subject to the terms of the Oculus license
11 agreement provided at the time of installation or download, or which
12 otherwise accompanies this software in either electronic or hard copy form.
14 *************************************************************************************/
16 #include "OVR_Win32_HIDDevice.h"
17 #include "OVR_Win32_DeviceManager.h"
19 #include "Kernel/OVR_System.h"
20 #include "Kernel/OVR_Log.h"
22 namespace OVR { namespace Win32 {
24 //-------------------------------------------------------------------------------------
25 // HIDDevicePathWrapper is a simple class used to extract HID device file path
26 // through SetupDiGetDeviceInterfaceDetail. We use a class since this is a bit messy.
27 class HIDDevicePathWrapper
28 {
29 SP_INTERFACE_DEVICE_DETAIL_DATA_A* pData;
30 public:
31 HIDDevicePathWrapper() : pData(0) { }
32 ~HIDDevicePathWrapper() { if (pData) OVR_FREE(pData); }
34 const char* GetPath() const { return pData ? pData->DevicePath : 0; }
36 bool InitPathFromInterfaceData(HDEVINFO hdevInfoSet, SP_DEVICE_INTERFACE_DATA* pidata);
37 };
39 bool HIDDevicePathWrapper::InitPathFromInterfaceData(HDEVINFO hdevInfoSet, SP_DEVICE_INTERFACE_DATA* pidata)
40 {
41 DWORD detailSize = 0;
42 // SetupDiGetDeviceInterfaceDetailA returns "not enough buffer error code"
43 // doe size request. Just check valid size.
44 SetupDiGetDeviceInterfaceDetailA(hdevInfoSet, pidata, NULL, 0, &detailSize, NULL);
45 if (!detailSize ||
46 ((pData = (SP_INTERFACE_DEVICE_DETAIL_DATA_A*)OVR_ALLOC(detailSize)) == 0))
47 return false;
48 pData->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA_A);
50 if (!SetupDiGetDeviceInterfaceDetailA(hdevInfoSet, pidata, pData, detailSize, NULL, NULL))
51 return false;
52 return true;
53 }
56 //-------------------------------------------------------------------------------------
57 // **** Win32::DeviceManager
59 HIDDeviceManager::HIDDeviceManager(DeviceManager* manager)
60 : Manager(manager)
61 {
62 hHidLib = ::LoadLibraryA("hid.dll");
63 OVR_ASSERT_LOG(hHidLib, ("Couldn't load Win32 'hid.dll'."));
65 OVR_RESOLVE_HIDFUNC(HidD_GetHidGuid);
66 OVR_RESOLVE_HIDFUNC(HidD_SetNumInputBuffers);
67 OVR_RESOLVE_HIDFUNC(HidD_GetFeature);
68 OVR_RESOLVE_HIDFUNC(HidD_SetFeature);
69 OVR_RESOLVE_HIDFUNC(HidD_GetAttributes);
70 OVR_RESOLVE_HIDFUNC(HidD_GetManufacturerString);
71 OVR_RESOLVE_HIDFUNC(HidD_GetProductString);
72 OVR_RESOLVE_HIDFUNC(HidD_GetSerialNumberString);
73 OVR_RESOLVE_HIDFUNC(HidD_GetPreparsedData);
74 OVR_RESOLVE_HIDFUNC(HidD_FreePreparsedData);
75 OVR_RESOLVE_HIDFUNC(HidP_GetCaps);
77 if (HidD_GetHidGuid)
78 HidD_GetHidGuid(&HidGuid);
79 }
81 HIDDeviceManager::~HIDDeviceManager()
82 {
83 ::FreeLibrary(hHidLib);
84 }
86 bool HIDDeviceManager::Initialize()
87 {
88 return true;
89 }
91 void HIDDeviceManager::Shutdown()
92 {
93 LogText("OVR::Win32::HIDDeviceManager - shutting down.\n");
94 }
96 bool HIDDeviceManager::Enumerate(HIDEnumerateVisitor* enumVisitor)
97 {
98 HDEVINFO hdevInfoSet;
99 SP_DEVICE_INTERFACE_DATA interfaceData;
100 interfaceData.cbSize = sizeof(interfaceData);
102 // Get handle to info data set describing all available HIDs.
103 hdevInfoSet = SetupDiGetClassDevsA(&HidGuid, NULL, NULL, DIGCF_INTERFACEDEVICE | DIGCF_PRESENT);
104 if (hdevInfoSet == INVALID_HANDLE_VALUE)
105 return false;
107 for(int deviceIndex = 0;
108 SetupDiEnumDeviceInterfaces(hdevInfoSet, NULL, &HidGuid, deviceIndex, &interfaceData);
109 deviceIndex++)
110 {
111 // For each device, we extract its file path and open it to get attributes,
112 // such as vendor and product id. If anything goes wrong, we move onto next device.
113 HIDDevicePathWrapper pathWrapper;
114 if (!pathWrapper.InitPathFromInterfaceData(hdevInfoSet, &interfaceData))
115 continue;
117 // Look for the device to check if it is already opened.
118 Ptr<DeviceCreateDesc> existingDevice = Manager->FindDevice(pathWrapper.GetPath());
119 // if device exists and it is opened then most likely the CreateHIDFile
120 // will fail; therefore, we just set Enumerated to 'true' and continue.
121 if (existingDevice && existingDevice->pDevice)
122 {
123 existingDevice->Enumerated = true;
124 continue;
125 }
127 // open device in non-exclusive mode for detection...
128 HANDLE hidDev = CreateHIDFile(pathWrapper.GetPath(), false);
129 if (hidDev == INVALID_HANDLE_VALUE)
130 continue;
132 HIDDeviceDesc devDesc;
133 devDesc.Path = pathWrapper.GetPath();
134 if (initVendorProductVersion(hidDev, &devDesc) &&
135 enumVisitor->MatchVendorProduct(devDesc.VendorId, devDesc.ProductId) &&
136 initUsage(hidDev, &devDesc))
137 {
138 initStrings(hidDev, &devDesc);
140 // Construct minimal device that the visitor callback can get feature reports from.
141 Win32::HIDDevice device(this, hidDev);
142 enumVisitor->Visit(device, devDesc);
143 }
145 ::CloseHandle(hidDev);
146 }
148 SetupDiDestroyDeviceInfoList(hdevInfoSet);
149 return true;
150 }
152 bool HIDDeviceManager::GetHIDDeviceDesc(const String& path, HIDDeviceDesc* pdevDesc) const
153 {
154 // open device in non-exclusive mode for detection...
155 HANDLE hidDev = CreateHIDFile(path, false);
156 if (hidDev == INVALID_HANDLE_VALUE)
157 return false;
159 pdevDesc->Path = path;
160 getFullDesc(hidDev, pdevDesc);
162 ::CloseHandle(hidDev);
163 return true;
164 }
166 OVR::HIDDevice* HIDDeviceManager::Open(const String& path)
167 {
169 Ptr<Win32::HIDDevice> device = *new Win32::HIDDevice(this);
171 if (device->HIDInitialize(path))
172 {
173 device->AddRef();
174 return device;
175 }
177 return NULL;
178 }
180 bool HIDDeviceManager::getFullDesc(HANDLE hidDev, HIDDeviceDesc* desc) const
181 {
183 if (!initVendorProductVersion(hidDev, desc))
184 {
185 return false;
186 }
188 if (!initUsage(hidDev, desc))
189 {
190 return false;
191 }
193 initStrings(hidDev, desc);
195 return true;
196 }
198 bool HIDDeviceManager::initVendorProductVersion(HANDLE hidDev, HIDDeviceDesc* desc) const
199 {
200 HIDD_ATTRIBUTES attr;
201 attr.Size = sizeof(attr);
202 if (!HidD_GetAttributes(hidDev, &attr))
203 return false;
204 desc->VendorId = attr.VendorID;
205 desc->ProductId = attr.ProductID;
206 desc->VersionNumber = attr.VersionNumber;
207 return true;
208 }
210 bool HIDDeviceManager::initUsage(HANDLE hidDev, HIDDeviceDesc* desc) const
211 {
212 bool result = false;
213 HIDP_CAPS caps;
214 HIDP_PREPARSED_DATA* preparsedData = 0;
216 if (!HidD_GetPreparsedData(hidDev, &preparsedData))
217 return false;
219 if (HidP_GetCaps(preparsedData, &caps) == HIDP_STATUS_SUCCESS)
220 {
221 desc->Usage = caps.Usage;
222 desc->UsagePage = caps.UsagePage;
223 result = true;
224 }
225 HidD_FreePreparsedData(preparsedData);
226 return result;
227 }
229 void HIDDeviceManager::initStrings(HANDLE hidDev, HIDDeviceDesc* desc) const
230 {
231 // Documentation mentions 126 as being the max for USB.
232 wchar_t strBuffer[196];
234 // HidD_Get*String functions return nothing in buffer on failure,
235 // so it's ok to do this without further error checking.
236 strBuffer[0] = 0;
237 HidD_GetManufacturerString(hidDev, strBuffer, sizeof(strBuffer));
238 desc->Manufacturer = strBuffer;
240 strBuffer[0] = 0;
241 HidD_GetProductString(hidDev, strBuffer, sizeof(strBuffer));
242 desc->Product = strBuffer;
244 strBuffer[0] = 0;
245 HidD_GetSerialNumberString(hidDev, strBuffer, sizeof(strBuffer));
246 desc->SerialNumber = strBuffer;
247 }
249 //-------------------------------------------------------------------------------------
250 // **** Win32::HIDDevice
252 HIDDevice::HIDDevice(HIDDeviceManager* manager)
253 : HIDManager(manager), inMinimalMode(false), Device(0), ReadRequested(false)
254 {
255 memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
256 }
258 // This is a minimal constructor used during enumeration for us to pass
259 // a HIDDevice to the visit function (so that it can query feature reports).
260 HIDDevice::HIDDevice(HIDDeviceManager* manager, HANDLE device)
261 : HIDManager(manager), inMinimalMode(true), Device(device), ReadRequested(true)
262 {
263 memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
264 }
266 HIDDevice::~HIDDevice()
267 {
268 if (!inMinimalMode)
269 {
270 HIDShutdown();
271 }
272 }
274 bool HIDDevice::HIDInitialize(const String& path)
275 {
277 DevDesc.Path = path;
279 if (!openDevice())
280 {
281 LogText("OVR::Win32::HIDDevice - Failed to open HIDDevice: ", path);
282 return false;
283 }
286 HIDManager->Manager->pThread->AddTicksNotifier(this);
287 HIDManager->Manager->pThread->AddMessageNotifier(this);
289 LogText("OVR::Win32::HIDDevice - Opened '%s'\n"
290 " Manufacturer:'%s' Product:'%s' Serial#:'%s'\n",
291 DevDesc.Path.ToCStr(),
292 DevDesc.Manufacturer.ToCStr(), DevDesc.Product.ToCStr(),
293 DevDesc.SerialNumber.ToCStr());
295 return true;
296 }
298 bool HIDDevice::initInfo()
299 {
300 // Device must have been successfully opened.
301 OVR_ASSERT(Device);
303 // Get report lengths.
304 HIDP_PREPARSED_DATA* preparsedData = 0;
305 if (!HIDManager->HidD_GetPreparsedData(Device, &preparsedData))
306 {
307 return false;
308 }
310 HIDP_CAPS caps;
311 if (HIDManager->HidP_GetCaps(preparsedData, &caps) != HIDP_STATUS_SUCCESS)
312 {
313 HIDManager->HidD_FreePreparsedData(preparsedData);
314 return false;
315 }
317 InputReportBufferLength = caps.InputReportByteLength;
318 OutputReportBufferLength = caps.OutputReportByteLength;
319 FeatureReportBufferLength= caps.FeatureReportByteLength;
320 HIDManager->HidD_FreePreparsedData(preparsedData);
322 if (ReadBufferSize < InputReportBufferLength)
323 {
324 OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer."));
325 return false;
326 }
328 // Get device desc.
329 if (!HIDManager->getFullDesc(Device, &DevDesc))
330 {
331 OVR_ASSERT_LOG(false, ("Failed to get device desc while initializing device."));
332 return false;
333 }
335 return true;
336 }
338 bool HIDDevice::openDevice()
339 {
340 memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
342 Device = HIDManager->CreateHIDFile(DevDesc.Path.ToCStr());
343 if (Device == INVALID_HANDLE_VALUE)
344 {
345 OVR_DEBUG_LOG(("Failed 'CreateHIDFile' while opening device, error = 0x%X.",
346 ::GetLastError()));
347 Device = 0;
348 return false;
349 }
351 if (!HIDManager->HidD_SetNumInputBuffers(Device, 128))
352 {
353 OVR_ASSERT_LOG(false, ("Failed 'HidD_SetNumInputBuffers' while initializing device."));
354 ::CloseHandle(Device);
355 Device = 0;
356 return false;
357 }
360 // Create a manual-reset non-signaled event.
361 ReadOverlapped.hEvent = ::CreateEvent(0, TRUE, FALSE, 0);
363 if (!ReadOverlapped.hEvent)
364 {
365 OVR_ASSERT_LOG(false, ("Failed to create event."));
366 ::CloseHandle(Device);
367 Device = 0;
368 return false;
369 }
371 if (!initInfo())
372 {
373 OVR_ASSERT_LOG(false, ("Failed to get HIDDevice info."));
375 ::CloseHandle(ReadOverlapped.hEvent);
376 memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
378 ::CloseHandle(Device);
379 Device = 0;
380 return false;
381 }
383 if (!initializeRead())
384 {
385 OVR_ASSERT_LOG(false, ("Failed to get intialize read for HIDDevice."));
387 ::CloseHandle(ReadOverlapped.hEvent);
388 memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
390 ::CloseHandle(Device);
391 Device = 0;
392 return false;
393 }
395 return true;
396 }
398 void HIDDevice::HIDShutdown()
399 {
401 HIDManager->Manager->pThread->RemoveTicksNotifier(this);
402 HIDManager->Manager->pThread->RemoveMessageNotifier(this);
404 closeDevice();
405 LogText("OVR::Win32::HIDDevice - Closed '%s'\n", DevDesc.Path.ToCStr());
406 }
408 bool HIDDevice::initializeRead()
409 {
411 if (!ReadRequested)
412 {
413 HIDManager->Manager->pThread->AddOverlappedEvent(this, ReadOverlapped.hEvent);
414 ReadRequested = true;
415 }
417 // Read resets the event...
418 while(::ReadFile(Device, ReadBuffer, InputReportBufferLength, 0, &ReadOverlapped))
419 {
420 processReadResult();
421 }
423 if (GetLastError() != ERROR_IO_PENDING)
424 {
425 // Some other error (such as unplugged).
426 closeDeviceOnIOError();
427 return false;
428 }
430 return true;
431 }
433 bool HIDDevice::processReadResult()
434 {
436 OVR_ASSERT(ReadRequested);
438 DWORD bytesRead = 0;
440 if (GetOverlappedResult(Device, &ReadOverlapped, &bytesRead, FALSE))
441 {
442 // We've got data.
443 if (Handler)
444 {
445 Handler->OnInputReport(ReadBuffer, bytesRead);
446 }
448 // TBD: Not needed?
449 // Event should be reset by Read call...
450 ReadOverlapped.Pointer = 0;
451 ReadOverlapped.Internal = 0;
452 ReadOverlapped.InternalHigh = 0;
453 return true;
454 }
455 else
456 {
457 if (GetLastError() != ERROR_IO_PENDING)
458 {
459 closeDeviceOnIOError();
460 return false;
461 }
462 }
464 return false;
465 }
467 void HIDDevice::closeDevice()
468 {
469 if (ReadRequested)
470 {
471 HIDManager->Manager->pThread->RemoveOverlappedEvent(this, ReadOverlapped.hEvent);
472 ReadRequested = false;
473 // Must call this to avoid Win32 assertion; CloseHandle is not enough.
474 ::CancelIo(Device);
475 }
477 ::CloseHandle(ReadOverlapped.hEvent);
478 memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
480 ::CloseHandle(Device);
481 Device = 0;
482 }
484 void HIDDevice::closeDeviceOnIOError()
485 {
486 LogText("OVR::Win32::HIDDevice - Lost connection to '%s'\n", DevDesc.Path.ToCStr());
487 closeDevice();
488 }
490 bool HIDDevice::SetFeatureReport(UByte* data, UInt32 length)
491 {
492 if (!ReadRequested)
493 return false;
495 return HIDManager->HidD_SetFeature(Device, data, (ULONG) length) != FALSE;
496 }
498 bool HIDDevice::GetFeatureReport(UByte* data, UInt32 length)
499 {
500 if (!ReadRequested)
501 return false;
503 return HIDManager->HidD_GetFeature(Device, data, (ULONG) length) != FALSE;
504 }
506 void HIDDevice::OnOverlappedEvent(HANDLE hevent)
507 {
508 OVR_UNUSED(hevent);
509 OVR_ASSERT(hevent == ReadOverlapped.hEvent);
511 if (processReadResult())
512 {
513 // Proceed to read again.
514 initializeRead();
515 }
516 }
518 UInt64 HIDDevice::OnTicks(UInt64 ticksMks)
519 {
520 if (Handler)
521 {
522 return Handler->OnTicks(ticksMks);
523 }
525 return DeviceManagerThread::Notifier::OnTicks(ticksMks);
526 }
528 bool HIDDevice::OnDeviceMessage(DeviceMessageType messageType,
529 const String& devicePath,
530 bool* error)
531 {
533 // Is this the correct device?
534 if (DevDesc.Path.CompareNoCase(devicePath) != 0)
535 {
536 return false;
537 }
539 if (messageType == DeviceMessage_DeviceAdded && !Device)
540 {
541 // A closed device has been re-added. Try to reopen.
542 if (!openDevice())
543 {
544 LogError("OVR::Win32::HIDDevice - Failed to reopen a device '%s' that was re-added.\n", devicePath.ToCStr());
545 *error = true;
546 return true;
547 }
549 LogText("OVR::Win32::HIDDevice - Reopened device '%s'\n", devicePath.ToCStr());
550 }
552 HIDHandler::HIDDeviceMessageType handlerMessageType = HIDHandler::HIDDeviceMessage_DeviceAdded;
553 if (messageType == DeviceMessage_DeviceAdded)
554 {
555 }
556 else if (messageType == DeviceMessage_DeviceRemoved)
557 {
558 handlerMessageType = HIDHandler::HIDDeviceMessage_DeviceRemoved;
559 }
560 else
561 {
562 OVR_ASSERT(0);
563 }
565 if (Handler)
566 {
567 Handler->OnDeviceMessage(handlerMessageType);
568 }
570 *error = false;
571 return true;
572 }
574 HIDDeviceManager* HIDDeviceManager::CreateInternal(Win32::DeviceManager* devManager)
575 {
577 if (!System::IsInitialized())
578 {
579 // Use custom message, since Log is not yet installed.
580 OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
581 LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
582 return 0;
583 }
585 Ptr<Win32::HIDDeviceManager> manager = *new Win32::HIDDeviceManager(devManager);
587 if (manager)
588 {
589 if (manager->Initialize())
590 {
591 manager->AddRef();
592 }
593 else
594 {
595 manager.Clear();
596 }
597 }
599 return manager.GetPtr();
600 }
602 } // namespace Win32
604 //-------------------------------------------------------------------------------------
605 // ***** Creation
607 // Creates a new HIDDeviceManager and initializes OVR.
608 HIDDeviceManager* HIDDeviceManager::Create()
609 {
610 OVR_ASSERT_LOG(false, ("Standalone mode not implemented yet."));
612 if (!System::IsInitialized())
613 {
614 // Use custom message, since Log is not yet installed.
615 OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
616 LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
617 return 0;
618 }
620 Ptr<Win32::HIDDeviceManager> manager = *new Win32::HIDDeviceManager(NULL);
622 if (manager)
623 {
624 if (manager->Initialize())
625 {
626 manager->AddRef();
627 }
628 else
629 {
630 manager.Clear();
631 }
632 }
634 return manager.GetPtr();
635 }
637 } // namespace OVR