oculus1
diff libovr/Src/osx/OVR_OSX_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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libovr/Src/osx/OVR_OSX_HIDDevice.cpp Sat Sep 14 16:14:59 2013 +0300 1.3 @@ -0,0 +1,899 @@ 1.4 +/************************************************************************************ 1.5 +Filename : OVR_OSX_HIDDevice.cpp 1.6 +Content : OSX HID device implementation. 1.7 +Created : February 26, 2013 1.8 +Authors : Lee Cooper 1.9 + 1.10 +Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved. 1.11 + 1.12 +Use of this software is subject to the terms of the Oculus license 1.13 +agreement provided at the time of installation or download, or which 1.14 +otherwise accompanies this software in either electronic or hard copy form. 1.15 + 1.16 +*************************************************************************************/ 1.17 + 1.18 +#include "OVR_OSX_HIDDevice.h" 1.19 + 1.20 +#include <IOKit/usb/IOUSBLib.h> 1.21 + 1.22 +namespace OVR { namespace OSX { 1.23 + 1.24 +static const UInt32 MAX_QUEUED_INPUT_REPORTS = 5; 1.25 + 1.26 +//------------------------------------------------------------------------------------- 1.27 +// **** OSX::DeviceManager 1.28 + 1.29 +HIDDeviceManager::HIDDeviceManager(DeviceManager* manager) 1.30 + : DevManager(manager) 1.31 +{ 1.32 + HIDManager = NULL; 1.33 +} 1.34 + 1.35 +HIDDeviceManager::~HIDDeviceManager() 1.36 +{ 1.37 +} 1.38 + 1.39 +CFRunLoopRef HIDDeviceManager::getRunLoop() 1.40 +{ 1.41 + if (DevManager != NULL) 1.42 + { 1.43 + return DevManager->pThread->GetRunLoop(); 1.44 + } 1.45 + 1.46 + return CFRunLoopGetCurrent(); 1.47 +} 1.48 + 1.49 +bool HIDDeviceManager::initializeManager() 1.50 +{ 1.51 + if (HIDManager != NULL) 1.52 + { 1.53 + return true; 1.54 + } 1.55 + 1.56 + HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); 1.57 + 1.58 + if (!HIDManager) 1.59 + { 1.60 + return false; 1.61 + } 1.62 + 1.63 + // Create a Matching Dictionary 1.64 + CFMutableDictionaryRef matchDict = 1.65 + CFDictionaryCreateMutable(kCFAllocatorDefault, 1.66 + 2, 1.67 + &kCFTypeDictionaryKeyCallBacks, 1.68 + &kCFTypeDictionaryValueCallBacks); 1.69 + 1.70 + // Specify a device manufacturer in the Matching Dictionary 1.71 + UInt32 vendorId = Oculus_VendorId; 1.72 + CFNumberRef vendorIdRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vendorId); 1.73 + CFDictionarySetValue(matchDict, 1.74 + CFSTR(kIOHIDVendorIDKey), 1.75 + vendorIdRef); 1.76 + // Register the Matching Dictionary to the HID Manager 1.77 + IOHIDManagerSetDeviceMatching(HIDManager, matchDict); 1.78 + CFRelease(vendorIdRef); 1.79 + CFRelease(matchDict); 1.80 + 1.81 + // Register a callback for USB device detection with the HID Manager 1.82 + IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, &staticDeviceMatchingCallback, this); 1.83 + 1.84 + IOHIDManagerScheduleWithRunLoop(HIDManager, getRunLoop(), kCFRunLoopDefaultMode); 1.85 + 1.86 + return true; 1.87 +} 1.88 + 1.89 +bool HIDDeviceManager::Initialize() 1.90 +{ 1.91 + return initializeManager(); 1.92 +} 1.93 + 1.94 +void HIDDeviceManager::Shutdown() 1.95 +{ 1.96 + OVR_ASSERT_LOG(HIDManager, ("Should have called 'Initialize' before 'Shutdown'.")); 1.97 + CFRelease(HIDManager); 1.98 + 1.99 + LogText("OVR::OSX::HIDDeviceManager - shutting down.\n"); 1.100 +} 1.101 + 1.102 +bool HIDDeviceManager::getIntProperty(IOHIDDeviceRef device, CFStringRef propertyName, SInt32* pResult) 1.103 +{ 1.104 + 1.105 + CFTypeRef ref = IOHIDDeviceGetProperty(device, propertyName); 1.106 + 1.107 + if (!ref) 1.108 + { 1.109 + return false; 1.110 + } 1.111 + 1.112 + if (CFGetTypeID(ref) != CFNumberGetTypeID()) 1.113 + { 1.114 + return false; 1.115 + } 1.116 + 1.117 + CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, pResult); 1.118 + 1.119 + return true; 1.120 +} 1.121 + 1.122 +bool HIDDeviceManager::initVendorProductVersion(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc) 1.123 +{ 1.124 + 1.125 + if (!getVendorId(device, &(pDevDesc->VendorId))) 1.126 + { 1.127 + return false; 1.128 + } 1.129 + 1.130 + if (!getProductId(device, &(pDevDesc->ProductId))) 1.131 + { 1.132 + return false; 1.133 + } 1.134 + 1.135 + return true; 1.136 +} 1.137 + 1.138 +bool HIDDeviceManager::initUsage(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc) 1.139 +{ 1.140 + 1.141 + SInt32 result; 1.142 + 1.143 + if (!getIntProperty(device, CFSTR(kIOHIDPrimaryUsagePageKey), &result)) 1.144 + { 1.145 + return false; 1.146 + } 1.147 + 1.148 + pDevDesc->UsagePage = result; 1.149 + 1.150 + 1.151 + if (!getIntProperty(device, CFSTR(kIOHIDPrimaryUsageKey), &result)) 1.152 + { 1.153 + return false; 1.154 + } 1.155 + 1.156 + pDevDesc->Usage = result; 1.157 + 1.158 + return true; 1.159 +} 1.160 + 1.161 +bool HIDDeviceManager::initSerialNumber(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc) 1.162 +{ 1.163 + return getSerialNumberString(device, &(pDevDesc->SerialNumber)); 1.164 +} 1.165 + 1.166 +bool HIDDeviceManager::initStrings(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc) 1.167 +{ 1.168 + 1.169 + // Regardless of whether they fail we'll try and get the remaining. 1.170 + getStringProperty(device, CFSTR(kIOHIDManufacturerKey), &(pDevDesc->Manufacturer)); 1.171 + getStringProperty(device, CFSTR(kIOHIDProductKey), &(pDevDesc->Product)); 1.172 + 1.173 + return true; 1.174 +} 1.175 + 1.176 +bool HIDDeviceManager::getStringProperty(IOHIDDeviceRef device, 1.177 + CFStringRef propertyName, 1.178 + String* pResult) 1.179 +{ 1.180 + 1.181 + CFStringRef str = (CFStringRef) IOHIDDeviceGetProperty(device, propertyName); 1.182 + 1.183 + if (!str) 1.184 + { 1.185 + return false; 1.186 + } 1.187 + 1.188 + CFIndex length = CFStringGetLength(str); 1.189 + CFRange range = CFRangeMake(0, length); 1.190 + 1.191 + // Test the conversion first to get required buffer size. 1.192 + CFIndex bufferLength; 1.193 + CFIndex numberOfChars = CFStringGetBytes(str, 1.194 + range, 1.195 + kCFStringEncodingUTF8, 1.196 + (char) '?', 1.197 + FALSE, 1.198 + NULL, 1.199 + 0, 1.200 + &bufferLength); 1.201 + 1.202 + if (numberOfChars == 0) 1.203 + { 1.204 + return false; 1.205 + } 1.206 + 1.207 + // Now allocate buffer. 1.208 + char* buffer = new char[bufferLength+1]; 1.209 + 1.210 + numberOfChars = CFStringGetBytes(str, 1.211 + range, 1.212 + kCFStringEncodingUTF8, 1.213 + (char) '?', 1.214 + FALSE, 1.215 + (UInt8*) buffer, 1.216 + bufferLength, 1.217 + NULL); 1.218 + OVR_ASSERT_LOG(numberOfChars != 0, ("CFStringGetBytes failed.")); 1.219 + 1.220 + buffer[bufferLength] = '\0'; 1.221 + *pResult = String(buffer); 1.222 + 1.223 + return true; 1.224 +} 1.225 + 1.226 +bool HIDDeviceManager::getVendorId(IOHIDDeviceRef device, UInt16* pResult) 1.227 +{ 1.228 + SInt32 result; 1.229 + 1.230 + if (!getIntProperty(device, CFSTR(kIOHIDVendorIDKey), &result)) 1.231 + { 1.232 + return false; 1.233 + } 1.234 + 1.235 + *pResult = result; 1.236 + 1.237 + return true; 1.238 +} 1.239 + 1.240 +bool HIDDeviceManager::getProductId(IOHIDDeviceRef device, UInt16* pResult) 1.241 +{ 1.242 + SInt32 result; 1.243 + 1.244 + if (!getIntProperty(device, CFSTR(kIOHIDProductIDKey), &result)) 1.245 + { 1.246 + return false; 1.247 + } 1.248 + 1.249 + *pResult = result; 1.250 + 1.251 + return true; 1.252 +} 1.253 + 1.254 +bool HIDDeviceManager::getLocationId(IOHIDDeviceRef device, SInt32* pResult) 1.255 +{ 1.256 + SInt32 result; 1.257 + 1.258 + if (!getIntProperty(device, CFSTR(kIOHIDLocationIDKey), &result)) 1.259 + { 1.260 + return false; 1.261 + } 1.262 + 1.263 + *pResult = result; 1.264 + 1.265 + return true; 1.266 +} 1.267 + 1.268 +bool HIDDeviceManager::getSerialNumberString(IOHIDDeviceRef device, String* pResult) 1.269 +{ 1.270 + 1.271 + if (!getStringProperty(device, CFSTR(kIOHIDSerialNumberKey), pResult)) 1.272 + { 1.273 + return false; 1.274 + } 1.275 + 1.276 + return true; 1.277 +} 1.278 + 1.279 +bool HIDDeviceManager::getPath(IOHIDDeviceRef device, String* pPath) 1.280 +{ 1.281 + 1.282 + String transport; 1.283 + if (!getStringProperty(device, CFSTR(kIOHIDTransportKey), &transport)) 1.284 + { 1.285 + return false; 1.286 + } 1.287 + 1.288 + UInt16 vendorId; 1.289 + if (!getVendorId(device, &vendorId)) 1.290 + { 1.291 + return false; 1.292 + } 1.293 + 1.294 + UInt16 productId; 1.295 + if (!getProductId(device, &productId)) 1.296 + { 1.297 + return false; 1.298 + } 1.299 + 1.300 + String serialNumber; 1.301 + if (!getSerialNumberString(device, &serialNumber)) 1.302 + { 1.303 + return false; 1.304 + } 1.305 + 1.306 + 1.307 + StringBuffer buffer; 1.308 + buffer.AppendFormat("%s:vid=%04hx:pid=%04hx:ser=%s", 1.309 + transport.ToCStr(), 1.310 + vendorId, 1.311 + productId, 1.312 + serialNumber.ToCStr()); 1.313 + 1.314 + *pPath = String(buffer); 1.315 + 1.316 + return true; 1.317 +} 1.318 + 1.319 +bool HIDDeviceManager::Enumerate(HIDEnumerateVisitor* enumVisitor) 1.320 +{ 1.321 + if (!initializeManager()) 1.322 + { 1.323 + return false; 1.324 + } 1.325 + 1.326 + 1.327 + CFSetRef deviceSet = IOHIDManagerCopyDevices(HIDManager); 1.328 + if (!deviceSet) 1.329 + return false; 1.330 + 1.331 + CFIndex deviceCount = CFSetGetCount(deviceSet); 1.332 + 1.333 + // Allocate a block of memory and read the set into it. 1.334 + IOHIDDeviceRef* devices = (IOHIDDeviceRef*) OVR_ALLOC(sizeof(IOHIDDeviceRef) * deviceCount); 1.335 + CFSetGetValues(deviceSet, (const void **) devices); 1.336 + 1.337 + 1.338 + // Iterate over devices. 1.339 + for (CFIndex deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++) 1.340 + { 1.341 + IOHIDDeviceRef hidDev = devices[deviceIndex]; 1.342 + 1.343 + if (!hidDev) 1.344 + { 1.345 + continue; 1.346 + } 1.347 + 1.348 + HIDDeviceDesc devDesc; 1.349 + 1.350 + if (getPath(hidDev, &(devDesc.Path)) && 1.351 + initVendorProductVersion(hidDev, &devDesc) && 1.352 + enumVisitor->MatchVendorProduct(devDesc.VendorId, devDesc.ProductId) && 1.353 + initUsage(hidDev, &devDesc)) 1.354 + { 1.355 + initStrings(hidDev, &devDesc); 1.356 + initSerialNumber(hidDev, &devDesc); 1.357 + 1.358 + // Look for the device to check if it is already opened. 1.359 + Ptr<DeviceCreateDesc> existingDevice = DevManager->FindHIDDevice(devDesc); 1.360 + // if device exists and it is opened then most likely the CreateHIDFile 1.361 + // will fail; therefore, we just set Enumerated to 'true' and continue. 1.362 + if (existingDevice && existingDevice->pDevice) 1.363 + { 1.364 + existingDevice->Enumerated = true; 1.365 + continue; 1.366 + } 1.367 + 1.368 + // Construct minimal device that the visitor callback can get feature reports from. 1.369 + OSX::HIDDevice device(this, hidDev); 1.370 + 1.371 + enumVisitor->Visit(device, devDesc); 1.372 + } 1.373 + } 1.374 + 1.375 + OVR_FREE(devices); 1.376 + CFRelease(deviceSet); 1.377 + 1.378 + return true; 1.379 +} 1.380 + 1.381 +OVR::HIDDevice* HIDDeviceManager::Open(const String& path) 1.382 +{ 1.383 + 1.384 + Ptr<OSX::HIDDevice> device = *new OSX::HIDDevice(this); 1.385 + 1.386 + if (!device->HIDInitialize(path)) 1.387 + { 1.388 + return NULL; 1.389 + } 1.390 + 1.391 + device->AddRef(); 1.392 + 1.393 + return device; 1.394 +} 1.395 + 1.396 +bool HIDDeviceManager::getFullDesc(IOHIDDeviceRef device, HIDDeviceDesc* desc) 1.397 +{ 1.398 + 1.399 + if (!initVendorProductVersion(device, desc)) 1.400 + { 1.401 + return false; 1.402 + } 1.403 + 1.404 + if (!initUsage(device, desc)) 1.405 + { 1.406 + return false; 1.407 + } 1.408 + 1.409 + if (!initSerialNumber(device, desc)) 1.410 + { 1.411 + return false; 1.412 + } 1.413 + 1.414 + initStrings(device, desc); 1.415 + 1.416 + return true; 1.417 +} 1.418 + 1.419 +// New USB device specified in the matching dictionary has been added (callback function) 1.420 +void HIDDeviceManager::staticDeviceMatchingCallback(void *inContext, 1.421 + IOReturn inResult, 1.422 + void *inSender, 1.423 + IOHIDDeviceRef inIOHIDDeviceRef) 1.424 +{ 1.425 + HIDDeviceManager* hidMgr = static_cast<HIDDeviceManager*>(inContext); 1.426 + HIDDeviceDesc hidDevDesc; 1.427 + hidMgr->getPath(inIOHIDDeviceRef, &hidDevDesc.Path); 1.428 + hidMgr->getFullDesc(inIOHIDDeviceRef, &hidDevDesc); 1.429 + 1.430 + hidMgr->DevManager->DetectHIDDevice(hidDevDesc); 1.431 +} 1.432 + 1.433 +//------------------------------------------------------------------------------------- 1.434 +// **** OSX::HIDDevice 1.435 + 1.436 +HIDDevice::HIDDevice(HIDDeviceManager* manager) 1.437 + : HIDManager(manager), InMinimalMode(false) 1.438 +{ 1.439 + Device = NULL; 1.440 + RepluggedNotificationPort = 0; 1.441 +} 1.442 + 1.443 +// This is a minimal constructor used during enumeration for us to pass 1.444 +// a HIDDevice to the visit function (so that it can query feature reports). 1.445 +HIDDevice::HIDDevice(HIDDeviceManager* manager, IOHIDDeviceRef device) 1.446 +: HIDManager(manager), Device(device), InMinimalMode(true) 1.447 +{ 1.448 + RepluggedNotificationPort = 0; 1.449 +} 1.450 + 1.451 +HIDDevice::~HIDDevice() 1.452 +{ 1.453 + if (!InMinimalMode) 1.454 + { 1.455 + HIDShutdown(); 1.456 + } 1.457 +} 1.458 + 1.459 +bool HIDDevice::HIDInitialize(const String& path) 1.460 +{ 1.461 + 1.462 + DevDesc.Path = path; 1.463 + 1.464 + if (!openDevice()) 1.465 + { 1.466 + LogText("OVR::OSX::HIDDevice - Failed to open HIDDevice: %s", path.ToCStr()); 1.467 + return false; 1.468 + } 1.469 + 1.470 + // Setup notification for when a device is unplugged and plugged back in. 1.471 + if (!setupDevicePluggedInNotification()) 1.472 + { 1.473 + LogText("OVR::OSX::HIDDevice - Failed to setup notification for when device plugged back in."); 1.474 + closeDevice(false); 1.475 + return false; 1.476 + } 1.477 + 1.478 + HIDManager->DevManager->pThread->AddTicksNotifier(this); 1.479 + 1.480 + 1.481 + LogText("OVR::OSX::HIDDevice - Opened '%s'\n" 1.482 + " Manufacturer:'%s' Product:'%s' Serial#:'%s'\n", 1.483 + DevDesc.Path.ToCStr(), 1.484 + DevDesc.Manufacturer.ToCStr(), DevDesc.Product.ToCStr(), 1.485 + DevDesc.SerialNumber.ToCStr()); 1.486 + 1.487 + return true; 1.488 +} 1.489 + 1.490 +bool HIDDevice::initInfo() 1.491 +{ 1.492 + // Device must have been successfully opened. 1.493 + OVR_ASSERT(Device); 1.494 + 1.495 + 1.496 + // Get report lengths. 1.497 + SInt32 bufferLength; 1.498 + bool getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxInputReportSizeKey), &bufferLength); 1.499 + OVR_ASSERT(getResult); 1.500 + InputReportBufferLength = (UInt16) bufferLength; 1.501 + 1.502 + getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxOutputReportSizeKey), &bufferLength); 1.503 + OVR_ASSERT(getResult); 1.504 + OutputReportBufferLength = (UInt16) bufferLength; 1.505 + 1.506 + getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxFeatureReportSizeKey), &bufferLength); 1.507 + OVR_ASSERT(getResult); 1.508 + FeatureReportBufferLength = (UInt16) bufferLength; 1.509 + 1.510 + 1.511 + if (ReadBufferSize < InputReportBufferLength) 1.512 + { 1.513 + OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer.")); 1.514 + return false; 1.515 + } 1.516 + 1.517 + // Get device desc. 1.518 + if (!HIDManager->getFullDesc(Device, &DevDesc)) 1.519 + { 1.520 + OVR_ASSERT_LOG(false, ("Failed to get device desc while initializing device.")); 1.521 + return false; 1.522 + } 1.523 + 1.524 + return true; 1.525 +} 1.526 + 1.527 +void HIDDevice::staticDeviceAddedCallback(void* pContext, io_iterator_t iterator) 1.528 +{ 1.529 + HIDDevice* pDevice = (HIDDevice*) pContext; 1.530 + pDevice->deviceAddedCallback(iterator); 1.531 +} 1.532 + 1.533 +void HIDDevice::deviceAddedCallback(io_iterator_t iterator) 1.534 +{ 1.535 + 1.536 + if (Device == NULL) 1.537 + { 1.538 + if (openDevice()) 1.539 + { 1.540 + LogText("OVR::OSX::HIDDevice - Reopened device : %s", DevDesc.Path.ToCStr()); 1.541 + 1.542 + Ptr<DeviceCreateDesc> existingHIDDev = HIDManager->DevManager->FindHIDDevice(DevDesc); 1.543 + if (existingHIDDev && existingHIDDev->pDevice) 1.544 + { 1.545 + HIDManager->DevManager->CallOnDeviceAdded(existingHIDDev); 1.546 + } 1.547 + } 1.548 + } 1.549 + 1.550 + // Reset callback. 1.551 + while (IOIteratorNext(iterator)) 1.552 + ; 1.553 +} 1.554 + 1.555 +bool HIDDevice::openDevice() 1.556 +{ 1.557 + 1.558 + // Have to iterate through devices again to generate paths. 1.559 + CFSetRef deviceSet = IOHIDManagerCopyDevices(HIDManager->HIDManager); 1.560 + CFIndex deviceCount = CFSetGetCount(deviceSet); 1.561 + 1.562 + // Allocate a block of memory and read the set into it. 1.563 + IOHIDDeviceRef* devices = (IOHIDDeviceRef*) OVR_ALLOC(sizeof(IOHIDDeviceRef) * deviceCount); 1.564 + CFSetGetValues(deviceSet, (const void **) devices); 1.565 + 1.566 + 1.567 + // Iterate over devices. 1.568 + IOHIDDeviceRef device = NULL; 1.569 + 1.570 + for (CFIndex deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++) 1.571 + { 1.572 + IOHIDDeviceRef tmpDevice = devices[deviceIndex]; 1.573 + 1.574 + if (!tmpDevice) 1.575 + { 1.576 + continue; 1.577 + } 1.578 + 1.579 + String path; 1.580 + if (!HIDManager->getPath(tmpDevice, &path)) 1.581 + { 1.582 + continue; 1.583 + } 1.584 + 1.585 + if (path == DevDesc.Path) 1.586 + { 1.587 + device = tmpDevice; 1.588 + break; 1.589 + } 1.590 + } 1.591 + 1.592 + 1.593 + OVR_FREE(devices); 1.594 + 1.595 + if (!device) 1.596 + { 1.597 + CFRelease(deviceSet); 1.598 + return false; 1.599 + } 1.600 + 1.601 + // Attempt to open device. 1.602 + if (IOHIDDeviceOpen(device, kIOHIDOptionsTypeSeizeDevice) 1.603 + != kIOReturnSuccess) 1.604 + { 1.605 + CFRelease(deviceSet); 1.606 + return false; 1.607 + } 1.608 + 1.609 + // Retain the device before we release the set. 1.610 + CFRetain(device); 1.611 + CFRelease(deviceSet); 1.612 + 1.613 + 1.614 + Device = device; 1.615 + 1.616 + 1.617 + if (!initInfo()) 1.618 + { 1.619 + IOHIDDeviceClose(Device, kIOHIDOptionsTypeSeizeDevice); 1.620 + CFRelease(Device); 1.621 + Device = NULL; 1.622 + return false; 1.623 + } 1.624 + 1.625 + 1.626 + // Setup the Run Loop and callbacks. 1.627 + IOHIDDeviceScheduleWithRunLoop(Device, 1.628 + HIDManager->getRunLoop(), 1.629 + kCFRunLoopDefaultMode); 1.630 + 1.631 + IOHIDDeviceRegisterInputReportCallback(Device, 1.632 + ReadBuffer, 1.633 + ReadBufferSize, 1.634 + staticHIDReportCallback, 1.635 + this); 1.636 + 1.637 + IOHIDDeviceRegisterRemovalCallback(Device, 1.638 + staticDeviceRemovedCallback, 1.639 + this); 1.640 + 1.641 + return true; 1.642 +} 1.643 + 1.644 +void HIDDevice::HIDShutdown() 1.645 +{ 1.646 + 1.647 + HIDManager->DevManager->pThread->RemoveTicksNotifier(this); 1.648 + 1.649 + if (Device != NULL) // Device may already have been closed if unplugged. 1.650 + { 1.651 + closeDevice(false); 1.652 + } 1.653 + 1.654 + IOObjectRelease(RepluggedNotification); 1.655 + if (RepluggedNotificationPort) 1.656 + IONotificationPortDestroy(RepluggedNotificationPort); 1.657 + 1.658 + LogText("OVR::OSX::HIDDevice - HIDShutdown '%s'\n", DevDesc.Path.ToCStr()); 1.659 +} 1.660 + 1.661 +bool HIDDevice::setupDevicePluggedInNotification() 1.662 +{ 1.663 + 1.664 + // Setup notification when devices are plugged in. 1.665 + RepluggedNotificationPort = IONotificationPortCreate(kIOMasterPortDefault); 1.666 + 1.667 + CFRunLoopSourceRef notificationRunLoopSource = 1.668 + IONotificationPortGetRunLoopSource(RepluggedNotificationPort); 1.669 + 1.670 + CFRunLoopAddSource(HIDManager->getRunLoop(), 1.671 + notificationRunLoopSource, 1.672 + kCFRunLoopDefaultMode); 1.673 + 1.674 + CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName); 1.675 + 1.676 + // Have to specify vendorId and productId. Doesn't seem to accept additional 1.677 + // things like serial number. 1.678 + SInt32 vendorId = DevDesc.VendorId; 1.679 + CFNumberRef numberRef = CFNumberCreate(kCFAllocatorDefault, 1.680 + kCFNumberSInt32Type, 1.681 + &vendorId); 1.682 + CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), numberRef); 1.683 + CFRelease(numberRef); 1.684 + 1.685 + SInt32 deviceProductId = DevDesc.ProductId; 1.686 + numberRef = CFNumberCreate(kCFAllocatorDefault, 1.687 + kCFNumberSInt32Type, 1.688 + &deviceProductId); 1.689 + CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), numberRef); 1.690 + CFRelease(numberRef); 1.691 + 1.692 + kern_return_t result = 1.693 + IOServiceAddMatchingNotification(RepluggedNotificationPort, 1.694 + kIOMatchedNotification, 1.695 + matchingDict, 1.696 + staticDeviceAddedCallback, 1.697 + this, 1.698 + &RepluggedNotification); 1.699 + 1.700 + if (result != KERN_SUCCESS) 1.701 + { 1.702 + CFRelease(RepluggedNotificationPort); 1.703 + RepluggedNotificationPort = 0; 1.704 + return false; 1.705 + } 1.706 + 1.707 + // Iterate through to arm. 1.708 + while (IOIteratorNext(RepluggedNotification)) 1.709 + { 1.710 + } 1.711 + 1.712 + return true; 1.713 +} 1.714 + 1.715 +void HIDDevice::closeDevice(bool wasUnplugged) 1.716 +{ 1.717 + OVR_ASSERT(Device != NULL); 1.718 + 1.719 + if (!wasUnplugged) 1.720 + { 1.721 + // Clear the registered callbacks. 1.722 + IOHIDDeviceRegisterInputReportCallback(Device, 1.723 + ReadBuffer, 1.724 + InputReportBufferLength, 1.725 + NULL, 1.726 + this); 1.727 + 1.728 + IOHIDDeviceRegisterRemovalCallback(Device, NULL, this); 1.729 + 1.730 + IOHIDDeviceUnscheduleFromRunLoop(Device, 1.731 + HIDManager->getRunLoop(), 1.732 + kCFRunLoopDefaultMode); 1.733 + IOHIDDeviceClose(Device, kIOHIDOptionsTypeNone); 1.734 + } 1.735 + 1.736 + CFRelease(Device); 1.737 + Device = NULL; 1.738 + 1.739 + LogText("OVR::OSX::HIDDevice - HID Device Closed '%s'\n", DevDesc.Path.ToCStr()); 1.740 +} 1.741 + 1.742 +void HIDDevice::staticHIDReportCallback(void* pContext, 1.743 + IOReturn result, 1.744 + void* pSender, 1.745 + IOHIDReportType reportType, 1.746 + uint32_t reportId, 1.747 + uint8_t* pReport, 1.748 + CFIndex reportLength) 1.749 +{ 1.750 + HIDDevice* pDevice = (HIDDevice*) pContext; 1.751 + return pDevice->hidReportCallback(pReport, (UInt32)reportLength); 1.752 +} 1.753 + 1.754 +void HIDDevice::hidReportCallback(UByte* pData, UInt32 length) 1.755 +{ 1.756 + 1.757 + // We got data. 1.758 + if (Handler) 1.759 + { 1.760 + Handler->OnInputReport(pData, length); 1.761 + } 1.762 +} 1.763 + 1.764 +void HIDDevice::staticDeviceRemovedCallback(void* pContext, IOReturn result, void* pSender) 1.765 +{ 1.766 + HIDDevice* pDevice = (HIDDevice*) pContext; 1.767 + pDevice->deviceRemovedCallback(); 1.768 +} 1.769 + 1.770 +void HIDDevice::deviceRemovedCallback() 1.771 +{ 1.772 + Ptr<HIDDevice> _this(this); // prevent from release 1.773 + 1.774 + Ptr<DeviceCreateDesc> existingHIDDev = HIDManager->DevManager->FindHIDDevice(DevDesc); 1.775 + if (existingHIDDev && existingHIDDev->pDevice) 1.776 + { 1.777 + HIDManager->DevManager->CallOnDeviceRemoved(existingHIDDev); 1.778 + } 1.779 + closeDevice(true); 1.780 +} 1.781 + 1.782 +CFStringRef HIDDevice::generateRunLoopModeString(IOHIDDeviceRef device) 1.783 +{ 1.784 + const UInt32 safeBuffSize = 256; 1.785 + char nameBuff[safeBuffSize]; 1.786 + OVR_sprintf(nameBuff, safeBuffSize, "%016lX", device); 1.787 + 1.788 + return CFStringCreateWithCString(NULL, nameBuff, kCFStringEncodingASCII); 1.789 +} 1.790 + 1.791 +bool HIDDevice::SetFeatureReport(UByte* data, UInt32 length) 1.792 +{ 1.793 + 1.794 + if (!Device) 1.795 + return false; 1.796 + 1.797 + UByte reportID = data[0]; 1.798 + 1.799 + if (reportID == 0) 1.800 + { 1.801 + // Not using reports so remove from data packet. 1.802 + data++; 1.803 + length--; 1.804 + } 1.805 + 1.806 + IOReturn result = IOHIDDeviceSetReport( Device, 1.807 + kIOHIDReportTypeFeature, 1.808 + reportID, 1.809 + data, 1.810 + length); 1.811 + 1.812 + return (result == kIOReturnSuccess); 1.813 +} 1.814 + 1.815 +bool HIDDevice::GetFeatureReport(UByte* data, UInt32 length) 1.816 +{ 1.817 + if (!Device) 1.818 + return false; 1.819 + 1.820 + CFIndex bufferLength = length; 1.821 + 1.822 + // Report id is in first byte of the buffer. 1.823 + IOReturn result = IOHIDDeviceGetReport(Device, kIOHIDReportTypeFeature, data[0], data, &bufferLength); 1.824 + 1.825 + return (result == kIOReturnSuccess); 1.826 +} 1.827 + 1.828 +UInt64 HIDDevice::OnTicks(UInt64 ticksMks) 1.829 +{ 1.830 + 1.831 + if (Handler) 1.832 + { 1.833 + return Handler->OnTicks(ticksMks); 1.834 + } 1.835 + 1.836 + return DeviceManagerThread::Notifier::OnTicks(ticksMks); 1.837 +} 1.838 + 1.839 +HIDDeviceManager* HIDDeviceManager::CreateInternal(OSX::DeviceManager* devManager) 1.840 +{ 1.841 + 1.842 + if (!System::IsInitialized()) 1.843 + { 1.844 + // Use custom message, since Log is not yet installed. 1.845 + OVR_DEBUG_STATEMENT(Log::GetDefaultLog()-> 1.846 + LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); ); 1.847 + return 0; 1.848 + } 1.849 + 1.850 + Ptr<OSX::HIDDeviceManager> manager = *new OSX::HIDDeviceManager(devManager); 1.851 + 1.852 + if (manager) 1.853 + { 1.854 + if (manager->Initialize()) 1.855 + { 1.856 + manager->AddRef(); 1.857 + } 1.858 + else 1.859 + { 1.860 + manager.Clear(); 1.861 + } 1.862 + } 1.863 + 1.864 + return manager.GetPtr(); 1.865 +} 1.866 + 1.867 +} // namespace OSX 1.868 + 1.869 +//------------------------------------------------------------------------------------- 1.870 +// ***** Creation 1.871 + 1.872 +// Creates a new HIDDeviceManager and initializes OVR. 1.873 +HIDDeviceManager* HIDDeviceManager::Create() 1.874 +{ 1.875 + OVR_ASSERT_LOG(false, ("Standalone mode not implemented yet.")); 1.876 + 1.877 + if (!System::IsInitialized()) 1.878 + { 1.879 + // Use custom message, since Log is not yet installed. 1.880 + OVR_DEBUG_STATEMENT(Log::GetDefaultLog()-> 1.881 + LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); ); 1.882 + return 0; 1.883 + } 1.884 + 1.885 + Ptr<OSX::HIDDeviceManager> manager = *new OSX::HIDDeviceManager(NULL); 1.886 + 1.887 + if (manager) 1.888 + { 1.889 + if (manager->Initialize()) 1.890 + { 1.891 + manager->AddRef(); 1.892 + } 1.893 + else 1.894 + { 1.895 + manager.Clear(); 1.896 + } 1.897 + } 1.898 + 1.899 + return manager.GetPtr(); 1.900 +} 1.901 + 1.902 +} // namespace OVR