oculus1

annotate libovr/Src/win32/OVR_Win32_HIDDevice.cpp @ 24:8419d8a13cee

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