nuclear@1: /************************************************************************************ nuclear@1: nuclear@1: Filename : OVR_DeviceImpl.h nuclear@1: Content : Partial back-end independent implementation of Device interfaces nuclear@1: Created : October 10, 2012 nuclear@1: Authors : Michael Antonov nuclear@1: nuclear@1: Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. nuclear@1: nuclear@1: Use of this software is subject to the terms of the Oculus license nuclear@1: agreement provided at the time of installation or download, or which nuclear@1: otherwise accompanies this software in either electronic or hard copy form. nuclear@1: nuclear@1: *************************************************************************************/ nuclear@1: nuclear@1: #include "OVR_DeviceImpl.h" nuclear@1: #include "Kernel/OVR_Atomic.h" nuclear@1: #include "Kernel/OVR_Log.h" nuclear@1: #include "Kernel/OVR_System.h" nuclear@1: nuclear@1: #include "OVR_DeviceImpl.h" nuclear@1: #include "OVR_SensorImpl.h" nuclear@1: #include "OVR_Profile.h" nuclear@1: nuclear@1: namespace OVR { nuclear@1: nuclear@1: nuclear@1: //------------------------------------------------------------------------------------- nuclear@1: // ***** SharedLock nuclear@1: nuclear@1: // This is a general purpose globally shared Lock implementation that should probably be nuclear@1: // moved to Kernel. nuclear@1: // May in theory busy spin-wait if we hit contention on first lock creation, nuclear@1: // but this shouldn't matter in practice since Lock* should be cached. nuclear@1: nuclear@1: nuclear@1: enum { LockInitMarker = 0xFFFFFFFF }; nuclear@1: nuclear@1: Lock* SharedLock::GetLockAddRef() nuclear@1: { nuclear@1: int oldUseCount; nuclear@1: nuclear@1: do { nuclear@1: oldUseCount = UseCount; nuclear@1: if (oldUseCount == LockInitMarker) nuclear@1: continue; nuclear@1: nuclear@1: if (oldUseCount == 0) nuclear@1: { nuclear@1: // Initialize marker nuclear@1: if (AtomicOps::CompareAndSet_Sync(&UseCount, 0, LockInitMarker)) nuclear@1: { nuclear@1: Construct(Buffer); nuclear@1: do { } nuclear@1: while (!AtomicOps::CompareAndSet_Sync(&UseCount, LockInitMarker, 1)); nuclear@1: return toLock(); nuclear@1: } nuclear@1: continue; nuclear@1: } nuclear@1: nuclear@1: } while (!AtomicOps::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount + 1)); nuclear@1: nuclear@1: return toLock(); nuclear@1: } nuclear@1: nuclear@1: void SharedLock::ReleaseLock(Lock* plock) nuclear@1: { nuclear@1: OVR_UNUSED(plock); nuclear@1: OVR_ASSERT(plock == toLock()); nuclear@1: nuclear@1: int oldUseCount; nuclear@1: nuclear@1: do { nuclear@1: oldUseCount = UseCount; nuclear@1: OVR_ASSERT(oldUseCount != LockInitMarker); nuclear@1: nuclear@1: if (oldUseCount == 1) nuclear@1: { nuclear@1: // Initialize marker nuclear@1: if (AtomicOps::CompareAndSet_Sync(&UseCount, 1, LockInitMarker)) nuclear@1: { nuclear@1: Destruct(toLock()); nuclear@1: nuclear@1: do { } nuclear@1: while (!AtomicOps::CompareAndSet_Sync(&UseCount, LockInitMarker, 0)); nuclear@1: nuclear@1: return; nuclear@1: } nuclear@1: continue; nuclear@1: } nuclear@1: nuclear@1: } while (!AtomicOps::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount - 1)); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: nuclear@1: //------------------------------------------------------------------------------------- nuclear@1: // ***** MessageHandler nuclear@1: nuclear@1: // Threading notes: nuclear@1: // The OnMessage() handler and SetMessageHandler are currently synchronized nuclear@1: // through a separately stored shared Lock object to avoid calling the handler nuclear@1: // from background thread while it's being removed. nuclear@1: nuclear@1: static SharedLock MessageHandlerSharedLock; nuclear@1: nuclear@1: nuclear@1: class MessageHandlerImpl nuclear@1: { nuclear@1: public: nuclear@1: MessageHandlerImpl() nuclear@1: : pLock(MessageHandlerSharedLock.GetLockAddRef()) nuclear@1: { nuclear@1: } nuclear@1: ~MessageHandlerImpl() nuclear@1: { nuclear@1: MessageHandlerSharedLock.ReleaseLock(pLock); nuclear@1: pLock = 0; nuclear@1: } nuclear@1: nuclear@1: static MessageHandlerImpl* FromHandler(MessageHandler* handler) nuclear@1: { return (MessageHandlerImpl*)&handler->Internal; } nuclear@1: static const MessageHandlerImpl* FromHandler(const MessageHandler* handler) nuclear@1: { return (const MessageHandlerImpl*)&handler->Internal; } nuclear@1: nuclear@1: // This lock is held while calling a handler and when we are applied/ nuclear@1: // removed from a device. nuclear@1: Lock* pLock; nuclear@1: // List of device we are applied to. nuclear@1: List UseList; nuclear@1: }; nuclear@1: nuclear@1: nuclear@1: MessageHandlerRef::MessageHandlerRef(DeviceBase* device) nuclear@1: : pLock(MessageHandlerSharedLock.GetLockAddRef()), pDevice(device), pHandler(0) nuclear@1: { nuclear@1: } nuclear@1: nuclear@1: MessageHandlerRef::~MessageHandlerRef() nuclear@1: { nuclear@1: { nuclear@1: Lock::Locker lockScope(pLock); nuclear@1: if (pHandler) nuclear@1: { nuclear@1: pHandler = 0; nuclear@1: RemoveNode(); nuclear@1: } nuclear@1: } nuclear@1: MessageHandlerSharedLock.ReleaseLock(pLock); nuclear@1: pLock = 0; nuclear@1: } nuclear@1: nuclear@1: void MessageHandlerRef::SetHandler(MessageHandler* handler) nuclear@1: { nuclear@1: OVR_ASSERT(!handler || nuclear@1: MessageHandlerImpl::FromHandler(handler)->pLock == pLock); nuclear@1: Lock::Locker lockScope(pLock); nuclear@1: SetHandler_NTS(handler); nuclear@1: } nuclear@1: nuclear@1: void MessageHandlerRef::SetHandler_NTS(MessageHandler* handler) nuclear@1: { nuclear@1: if (pHandler != handler) nuclear@1: { nuclear@1: if (pHandler) nuclear@1: RemoveNode(); nuclear@1: pHandler = handler; nuclear@1: nuclear@1: if (handler) nuclear@1: { nuclear@1: MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(handler); nuclear@1: handlerImpl->UseList.PushBack(this); nuclear@1: } nuclear@1: // TBD: Call notifier on device? nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: nuclear@1: MessageHandler::MessageHandler() nuclear@1: { nuclear@1: OVR_COMPILER_ASSERT(sizeof(Internal) > sizeof(MessageHandlerImpl)); nuclear@1: Construct(Internal); nuclear@1: } nuclear@1: nuclear@1: MessageHandler::~MessageHandler() nuclear@1: { nuclear@1: MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this); nuclear@1: { nuclear@1: Lock::Locker lockedScope(handlerImpl->pLock); nuclear@1: OVR_ASSERT_LOG(handlerImpl->UseList.IsEmpty(), nuclear@1: ("~MessageHandler %p - Handler still active; call RemoveHandlerFromDevices", this)); nuclear@1: } nuclear@1: nuclear@1: Destruct(handlerImpl); nuclear@1: } nuclear@1: nuclear@1: bool MessageHandler::IsHandlerInstalled() const nuclear@1: { nuclear@1: const MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this); nuclear@1: Lock::Locker lockedScope(handlerImpl->pLock); nuclear@1: return handlerImpl->UseList.IsEmpty() != true; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: void MessageHandler::RemoveHandlerFromDevices() nuclear@1: { nuclear@1: MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this); nuclear@1: Lock::Locker lockedScope(handlerImpl->pLock); nuclear@1: nuclear@1: while(!handlerImpl->UseList.IsEmpty()) nuclear@1: { nuclear@1: MessageHandlerRef* use = handlerImpl->UseList.GetFirst(); nuclear@1: use->SetHandler_NTS(0); nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: Lock* MessageHandler::GetHandlerLock() const nuclear@1: { nuclear@1: const MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this); nuclear@1: return handlerImpl->pLock; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: //------------------------------------------------------------------------------------- nuclear@1: // ***** DeviceBase nuclear@1: nuclear@1: nuclear@1: // Delegate relevant implementation to DeviceRectord to avoid re-implementation in nuclear@1: // every derived Device. nuclear@1: void DeviceBase::AddRef() nuclear@1: { nuclear@1: getDeviceCommon()->DeviceAddRef(); nuclear@1: } nuclear@1: void DeviceBase::Release() nuclear@1: { nuclear@1: getDeviceCommon()->DeviceRelease(); nuclear@1: } nuclear@1: DeviceBase* DeviceBase::GetParent() const nuclear@1: { nuclear@1: return getDeviceCommon()->pParent.GetPtr(); nuclear@1: } nuclear@1: DeviceManager* DeviceBase::GetManager() const nuclear@1: { nuclear@1: return getDeviceCommon()->pCreateDesc->GetManagerImpl(); nuclear@1: } nuclear@1: nuclear@1: void DeviceBase::SetMessageHandler(MessageHandler* handler) nuclear@1: { nuclear@1: getDeviceCommon()->HandlerRef.SetHandler(handler); nuclear@1: } nuclear@1: MessageHandler* DeviceBase::GetMessageHandler() const nuclear@1: { nuclear@1: return getDeviceCommon()->HandlerRef.GetHandler(); nuclear@1: } nuclear@1: nuclear@1: DeviceType DeviceBase::GetType() const nuclear@1: { nuclear@1: return getDeviceCommon()->pCreateDesc->Type; nuclear@1: } nuclear@1: nuclear@1: bool DeviceBase::GetDeviceInfo(DeviceInfo* info) const nuclear@1: { nuclear@1: return getDeviceCommon()->pCreateDesc->GetDeviceInfo(info); nuclear@1: //info->Name[0] = 0; nuclear@1: //return false; nuclear@1: } nuclear@1: nuclear@1: // returns the MessageHandler's lock nuclear@1: Lock* DeviceBase::GetHandlerLock() const nuclear@1: { nuclear@1: return getDeviceCommon()->HandlerRef.GetLock(); nuclear@1: } nuclear@1: nuclear@1: // Derive DeviceManagerCreateDesc to provide abstract function implementation. nuclear@1: class DeviceManagerCreateDesc : public DeviceCreateDesc nuclear@1: { nuclear@1: public: nuclear@1: DeviceManagerCreateDesc(DeviceFactory* factory) nuclear@1: : DeviceCreateDesc(factory, Device_Manager) { } nuclear@1: nuclear@1: // We don't need there on Manager since it isn't assigned to DeviceHandle. nuclear@1: virtual DeviceCreateDesc* Clone() const { return 0; } nuclear@1: virtual MatchResult MatchDevice(const DeviceCreateDesc&, nuclear@1: DeviceCreateDesc**) const { return Match_None; } nuclear@1: virtual DeviceBase* NewDeviceInstance() { return 0; } nuclear@1: virtual bool GetDeviceInfo(DeviceInfo*) const { return false; } nuclear@1: }; nuclear@1: nuclear@1: //------------------------------------------------------------------------------------- nuclear@1: // ***** DeviceManagerImpl nuclear@1: nuclear@1: DeviceManagerImpl::DeviceManagerImpl() nuclear@1: : DeviceImpl(CreateManagerDesc(), 0) nuclear@1: //,DeviceCreateDescList(pCreateDesc ? pCreateDesc->pLock : 0) nuclear@1: { nuclear@1: if (pCreateDesc) nuclear@1: { nuclear@1: pCreateDesc->pLock->pManager = this; nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: DeviceManagerImpl::~DeviceManagerImpl() nuclear@1: { nuclear@1: // Shutdown must've been called. nuclear@1: OVR_ASSERT(!pCreateDesc->pDevice); nuclear@1: nuclear@1: // Remove all factories nuclear@1: while(!Factories.IsEmpty()) nuclear@1: { nuclear@1: DeviceFactory* factory = Factories.GetFirst(); nuclear@1: factory->RemovedFromManager(); nuclear@1: factory->RemoveNode(); nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: DeviceCreateDesc* DeviceManagerImpl::CreateManagerDesc() nuclear@1: { nuclear@1: DeviceCreateDesc* managerDesc = new DeviceManagerCreateDesc(0); nuclear@1: if (managerDesc) nuclear@1: { nuclear@1: managerDesc->pLock = *new DeviceManagerLock; nuclear@1: } nuclear@1: return managerDesc; nuclear@1: } nuclear@1: nuclear@1: bool DeviceManagerImpl::Initialize(DeviceBase* parent) nuclear@1: { nuclear@1: OVR_UNUSED(parent); nuclear@1: if (!pCreateDesc || !pCreateDesc->pLock) nuclear@1: return false; nuclear@1: nuclear@1: pProfileManager = *ProfileManager::Create(); nuclear@1: nuclear@1: return true; nuclear@1: } nuclear@1: nuclear@1: void DeviceManagerImpl::Shutdown() nuclear@1: { nuclear@1: // Remove all device descriptors from list while the lock is held. nuclear@1: // Some descriptors may survive longer due to handles. nuclear@1: while(!Devices.IsEmpty()) nuclear@1: { nuclear@1: DeviceCreateDesc* devDesc = Devices.GetFirst(); nuclear@1: OVR_ASSERT(!devDesc->pDevice); // Manager shouldn't be dying while Device exists. nuclear@1: devDesc->Enumerated = false; nuclear@1: devDesc->RemoveNode(); nuclear@1: devDesc->pNext = devDesc->pPrev = 0; nuclear@1: nuclear@1: if (devDesc->HandleCount == 0) nuclear@1: { nuclear@1: delete devDesc; nuclear@1: } nuclear@1: } nuclear@1: Devices.Clear(); nuclear@1: nuclear@1: // These must've been cleared by caller. nuclear@1: OVR_ASSERT(pCreateDesc->pDevice == 0); nuclear@1: OVR_ASSERT(pCreateDesc->pLock->pManager == 0); nuclear@1: nuclear@1: pProfileManager.Clear(); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: // Callbacks for DeviceCreation/Release nuclear@1: DeviceBase* DeviceManagerImpl::CreateDevice_MgrThread(DeviceCreateDesc* createDesc, DeviceBase* parent) nuclear@1: { nuclear@1: // Calls to DeviceManagerImpl::CreateDevice are enqueued with wait while holding pManager, nuclear@1: // so 'this' must remain valid. nuclear@1: OVR_ASSERT(createDesc->pLock->pManager); nuclear@1: nuclear@1: Lock::Locker devicesLock(GetLock()); nuclear@1: nuclear@1: // If device already exists, just AddRef to it. nuclear@1: if (createDesc->pDevice) nuclear@1: { nuclear@1: createDesc->pDevice->AddRef(); nuclear@1: return createDesc->pDevice; nuclear@1: } nuclear@1: nuclear@1: if (!parent) nuclear@1: parent = this; nuclear@1: nuclear@1: DeviceBase* device = createDesc->NewDeviceInstance(); nuclear@1: nuclear@1: if (device) nuclear@1: { nuclear@1: if (device->getDeviceCommon()->Initialize(parent)) nuclear@1: { nuclear@1: createDesc->pDevice = device; nuclear@1: } nuclear@1: else nuclear@1: { nuclear@1: // Don't go through Release() to avoid PushCall behaviour, nuclear@1: // as it is not needed here. nuclear@1: delete device; nuclear@1: device = 0; nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: return device; nuclear@1: } nuclear@1: nuclear@1: Void DeviceManagerImpl::ReleaseDevice_MgrThread(DeviceBase* device) nuclear@1: { nuclear@1: // descKeepAlive will keep ManagerLock object alive as well, nuclear@1: // allowing us to exit gracefully. nuclear@1: Ptr descKeepAlive; nuclear@1: Lock::Locker devicesLock(GetLock()); nuclear@1: DeviceCommon* devCommon = device->getDeviceCommon(); nuclear@1: nuclear@1: while(1) nuclear@1: { nuclear@1: UInt32 refCount = devCommon->RefCount; nuclear@1: nuclear@1: if (refCount > 1) nuclear@1: { nuclear@1: if (devCommon->RefCount.CompareAndSet_NoSync(refCount, refCount-1)) nuclear@1: { nuclear@1: // We decreented from initial count higher then 1; nuclear@1: // nothing else to do. nuclear@1: return 0; nuclear@1: } nuclear@1: } nuclear@1: else if (devCommon->RefCount.CompareAndSet_NoSync(1, 0)) nuclear@1: { nuclear@1: // { 1 -> 0 } decrement succeded. Destroy this device. nuclear@1: break; nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: // At this point, may be releasing the device manager itself. nuclear@1: // This does not matter, however, since shutdown logic is the same nuclear@1: // in both cases. DeviceManager::Shutdown with begin shutdown process for nuclear@1: // the internal manager thread, which will eventually destroy itself. nuclear@1: // TBD: Clean thread shutdown. nuclear@1: descKeepAlive = devCommon->pCreateDesc; nuclear@1: descKeepAlive->pDevice = 0; nuclear@1: devCommon->Shutdown(); nuclear@1: delete device; nuclear@1: return 0; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: nuclear@1: Void DeviceManagerImpl::EnumerateAllFactoryDevices() nuclear@1: { nuclear@1: // 1. Mark matching devices as NOT enumerated. nuclear@1: // 2. Call factory to enumerate all HW devices, adding any device that nuclear@1: // was not matched. nuclear@1: // 3. Remove non-matching devices. nuclear@1: nuclear@1: Lock::Locker deviceLock(GetLock()); nuclear@1: nuclear@1: DeviceCreateDesc* devDesc, *nextdevDesc; nuclear@1: nuclear@1: // 1. nuclear@1: for(devDesc = Devices.GetFirst(); nuclear@1: !Devices.IsNull(devDesc); devDesc = devDesc->pNext) nuclear@1: { nuclear@1: //if (devDesc->pFactory == factory) nuclear@1: devDesc->Enumerated = false; nuclear@1: } nuclear@1: nuclear@1: // 2. nuclear@1: DeviceFactory* factory = Factories.GetFirst(); nuclear@1: while(!Factories.IsNull(factory)) nuclear@1: { nuclear@1: EnumerateFactoryDevices(factory); nuclear@1: factory = factory->pNext; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: // 3. nuclear@1: for(devDesc = Devices.GetFirst(); nuclear@1: !Devices.IsNull(devDesc); devDesc = nextdevDesc) nuclear@1: { nuclear@1: // In case 'devDesc' gets removed. nuclear@1: nextdevDesc = devDesc->pNext; nuclear@1: nuclear@1: // Note, device might be not enumerated since it is opened and nuclear@1: // in use! Do NOT notify 'device removed' in this case (!AB) nuclear@1: if (!devDesc->Enumerated) nuclear@1: { nuclear@1: // This deletes the devDesc for HandleCount == 0 due to Release in DeviceHandle. nuclear@1: CallOnDeviceRemoved(devDesc); nuclear@1: nuclear@1: /* nuclear@1: if (devDesc->HandleCount == 0) nuclear@1: { nuclear@1: // Device must be dead if it ever existed, since it AddRefs to us. nuclear@1: // ~DeviceCreateDesc removes its node from list. nuclear@1: OVR_ASSERT(!devDesc->pDevice); nuclear@1: delete devDesc; nuclear@1: } nuclear@1: */ nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: return 0; nuclear@1: } nuclear@1: nuclear@1: Ptr DeviceManagerImpl::AddDevice_NeedsLock( nuclear@1: const DeviceCreateDesc& createDesc) nuclear@1: { nuclear@1: // If found, mark as enumerated and we are done. nuclear@1: DeviceCreateDesc* descCandidate = 0; nuclear@1: nuclear@1: for(DeviceCreateDesc* devDesc = Devices.GetFirst(); nuclear@1: !Devices.IsNull(devDesc); devDesc = devDesc->pNext) nuclear@1: { nuclear@1: DeviceCreateDesc::MatchResult mr = devDesc->MatchDevice(createDesc, &descCandidate); nuclear@1: if (mr == DeviceCreateDesc::Match_Found) nuclear@1: { nuclear@1: devDesc->Enumerated = true; nuclear@1: if (!devDesc->pDevice) nuclear@1: CallOnDeviceAdded(devDesc); nuclear@1: return devDesc; nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: // Update candidate (this may involve writing fields to HMDDevice createDesc). nuclear@1: if (descCandidate) nuclear@1: { nuclear@1: bool newDevice = false; nuclear@1: if (descCandidate->UpdateMatchedCandidate(createDesc, &newDevice)) nuclear@1: { nuclear@1: descCandidate->Enumerated = true; nuclear@1: if (!descCandidate->pDevice || newDevice) nuclear@1: CallOnDeviceAdded(descCandidate); nuclear@1: return descCandidate; nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: // If not found, add new device. nuclear@1: // - This stores a new descriptor with nuclear@1: // {pDevice = 0, HandleCount = 1, Enumerated = true} nuclear@1: DeviceCreateDesc* desc = createDesc.Clone(); nuclear@1: desc->pLock = pCreateDesc->pLock; nuclear@1: Devices.PushBack(desc); nuclear@1: desc->Enumerated = true; nuclear@1: nuclear@1: CallOnDeviceAdded(desc); nuclear@1: nuclear@1: return desc; nuclear@1: } nuclear@1: nuclear@1: Ptr DeviceManagerImpl::FindDevice( nuclear@1: const String& path, nuclear@1: DeviceType deviceType) nuclear@1: { nuclear@1: Lock::Locker deviceLock(GetLock()); nuclear@1: DeviceCreateDesc* devDesc; nuclear@1: nuclear@1: for (devDesc = Devices.GetFirst(); nuclear@1: !Devices.IsNull(devDesc); devDesc = devDesc->pNext) nuclear@1: { nuclear@1: if ((deviceType == Device_None || deviceType == devDesc->Type) && nuclear@1: devDesc->MatchDevice(path)) nuclear@1: return devDesc; nuclear@1: } nuclear@1: return NULL; nuclear@1: } nuclear@1: nuclear@1: Ptr DeviceManagerImpl::FindHIDDevice(const HIDDeviceDesc& hidDevDesc) nuclear@1: { nuclear@1: Lock::Locker deviceLock(GetLock()); nuclear@1: DeviceCreateDesc* devDesc; nuclear@1: nuclear@1: for (devDesc = Devices.GetFirst(); nuclear@1: !Devices.IsNull(devDesc); devDesc = devDesc->pNext) nuclear@1: { nuclear@1: if (devDesc->MatchHIDDevice(hidDevDesc)) nuclear@1: return devDesc; nuclear@1: } nuclear@1: return NULL; nuclear@1: } nuclear@1: nuclear@1: void DeviceManagerImpl::DetectHIDDevice(const HIDDeviceDesc& hidDevDesc) nuclear@1: { nuclear@1: Lock::Locker deviceLock(GetLock()); nuclear@1: DeviceFactory* factory = Factories.GetFirst(); nuclear@1: while(!Factories.IsNull(factory)) nuclear@1: { nuclear@1: if (factory->DetectHIDDevice(this, hidDevDesc)) nuclear@1: break; nuclear@1: factory = factory->pNext; nuclear@1: } nuclear@1: nuclear@1: } nuclear@1: nuclear@1: // Enumerates devices for a particular factory. nuclear@1: Void DeviceManagerImpl::EnumerateFactoryDevices(DeviceFactory* factory) nuclear@1: { nuclear@1: nuclear@1: class FactoryEnumerateVisitor : public DeviceFactory::EnumerateVisitor nuclear@1: { nuclear@1: DeviceManagerImpl* pManager; nuclear@1: DeviceFactory* pFactory; nuclear@1: public: nuclear@1: FactoryEnumerateVisitor(DeviceManagerImpl* manager, DeviceFactory* factory) nuclear@1: : pManager(manager), pFactory(factory) { } nuclear@1: nuclear@1: virtual void Visit(const DeviceCreateDesc& createDesc) nuclear@1: { nuclear@1: pManager->AddDevice_NeedsLock(createDesc); nuclear@1: } nuclear@1: }; nuclear@1: nuclear@1: FactoryEnumerateVisitor newDeviceVisitor(this, factory); nuclear@1: factory->EnumerateDevices(newDeviceVisitor); nuclear@1: nuclear@1: nuclear@1: return 0; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: DeviceEnumerator<> DeviceManagerImpl::EnumerateDevicesEx(const DeviceEnumerationArgs& args) nuclear@1: { nuclear@1: Lock::Locker deviceLock(GetLock()); nuclear@1: nuclear@1: if (Devices.IsEmpty()) nuclear@1: return DeviceEnumerator<>(); nuclear@1: nuclear@1: DeviceCreateDesc* firstDeviceDesc = Devices.GetFirst(); nuclear@1: DeviceEnumerator<> e = enumeratorFromHandle(DeviceHandle(firstDeviceDesc), args); nuclear@1: nuclear@1: if (!args.MatchRule(firstDeviceDesc->Type, firstDeviceDesc->Enumerated)) nuclear@1: { nuclear@1: e.Next(); nuclear@1: } nuclear@1: nuclear@1: return e; nuclear@1: } nuclear@1: nuclear@1: //------------------------------------------------------------------------------------- nuclear@1: // ***** DeviceCommon nuclear@1: nuclear@1: void DeviceCommon::DeviceAddRef() nuclear@1: { nuclear@1: RefCount++; nuclear@1: } nuclear@1: nuclear@1: void DeviceCommon::DeviceRelease() nuclear@1: { nuclear@1: while(1) nuclear@1: { nuclear@1: UInt32 refCount = RefCount; nuclear@1: OVR_ASSERT(refCount > 0); nuclear@1: nuclear@1: if (refCount == 1) nuclear@1: { nuclear@1: DeviceManagerImpl* manager = pCreateDesc->GetManagerImpl(); nuclear@1: ThreadCommandQueue* queue = manager->GetThreadQueue(); nuclear@1: nuclear@1: // Enqueue ReleaseDevice for {1 -> 0} transition with no wait. nuclear@1: // We pass our reference ownership into the queue to destroy. nuclear@1: // It's in theory possible for another thread to re-steal our device reference, nuclear@1: // but that is checked for atomically in DeviceManagerImpl::ReleaseDevice. nuclear@1: if (!queue->PushCall(manager, &DeviceManagerImpl::ReleaseDevice_MgrThread, nuclear@1: pCreateDesc->pDevice)) nuclear@1: { nuclear@1: // PushCall shouldn't fail because background thread runs while manager is nuclear@1: // alive and we are holding Manager alive through pParent chain. nuclear@1: OVR_ASSERT(false); nuclear@1: } nuclear@1: nuclear@1: // Warning! At his point everything, including manager, may be dead. nuclear@1: break; nuclear@1: } nuclear@1: else if (RefCount.CompareAndSet_NoSync(refCount, refCount-1)) nuclear@1: { nuclear@1: break; nuclear@1: } nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: nuclear@1: nuclear@1: //------------------------------------------------------------------------------------- nuclear@1: // ***** DeviceCreateDesc nuclear@1: nuclear@1: nuclear@1: void DeviceCreateDesc::AddRef() nuclear@1: { nuclear@1: // Technically, HandleCount { 0 -> 1 } transition can only happen during Lock, nuclear@1: // but we leave this to caller to worry about (happens during enumeration). nuclear@1: HandleCount++; nuclear@1: } nuclear@1: nuclear@1: void DeviceCreateDesc::Release() nuclear@1: { nuclear@1: while(1) nuclear@1: { nuclear@1: UInt32 handleCount = HandleCount; nuclear@1: // HandleCount must obviously be >= 1, since we are releasing it. nuclear@1: OVR_ASSERT(handleCount > 0); nuclear@1: nuclear@1: // {1 -> 0} transition may cause us to be destroyed, so require a lock. nuclear@1: if (handleCount == 1) nuclear@1: { nuclear@1: Ptr lockKeepAlive; nuclear@1: Lock::Locker deviceLockScope(GetLock()); nuclear@1: nuclear@1: if (!HandleCount.CompareAndSet_NoSync(handleCount, 0)) nuclear@1: continue; nuclear@1: nuclear@1: OVR_ASSERT(pDevice == 0); nuclear@1: nuclear@1: // Destroy *this if the manager was destroyed already, or Enumerated nuclear@1: // is false (device no longer available). nuclear@1: if (!GetManagerImpl() || !Enumerated) nuclear@1: { nuclear@1: lockKeepAlive = pLock; nuclear@1: nuclear@1: // Remove from manager list (only matters for !Enumerated). nuclear@1: if (pNext) nuclear@1: { nuclear@1: RemoveNode(); nuclear@1: pNext = pPrev = 0; nuclear@1: } nuclear@1: nuclear@1: delete this; nuclear@1: } nuclear@1: nuclear@1: // Available DeviceCreateDesc may survive with { HandleCount == 0 }, nuclear@1: // in case it might be enumerated again later. nuclear@1: break; nuclear@1: } nuclear@1: else if (HandleCount.CompareAndSet_NoSync(handleCount, handleCount-1)) nuclear@1: { nuclear@1: break; nuclear@1: } nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: HMDDevice* HMDDevice::Disconnect(SensorDevice* psensor) nuclear@1: { nuclear@1: if (!psensor) nuclear@1: return NULL; nuclear@1: nuclear@1: OVR::DeviceManager* manager = GetManager(); nuclear@1: if (manager) nuclear@1: { nuclear@1: //DeviceManagerImpl* mgrImpl = static_cast(manager); nuclear@1: Ptr desc = getDeviceCommon()->pCreateDesc; nuclear@1: if (desc) nuclear@1: { nuclear@1: class Visitor : public DeviceFactory::EnumerateVisitor nuclear@1: { nuclear@1: Ptr Desc; nuclear@1: public: nuclear@1: Visitor(DeviceCreateDesc* desc) : Desc(desc) {} nuclear@1: virtual void Visit(const DeviceCreateDesc& createDesc) nuclear@1: { nuclear@1: Lock::Locker lock(Desc->GetLock()); nuclear@1: Desc->UpdateMatchedCandidate(createDesc); nuclear@1: } nuclear@1: } visitor(desc); nuclear@1: //SensorDeviceImpl* sImpl = static_cast(psensor); nuclear@1: nuclear@1: SensorDisplayInfoImpl displayInfo; nuclear@1: nuclear@1: if (psensor->GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize)) nuclear@1: { nuclear@1: displayInfo.Unpack(); nuclear@1: nuclear@1: // If we got display info, try to match / create HMDDevice as well nuclear@1: // so that sensor settings give preference. nuclear@1: if (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt) nuclear@1: { nuclear@1: SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo(displayInfo, visitor); nuclear@1: } nuclear@1: } nuclear@1: } nuclear@1: } nuclear@1: return this; nuclear@1: } nuclear@1: nuclear@1: bool HMDDevice::IsDisconnected() const nuclear@1: { nuclear@1: OVR::HMDInfo info; nuclear@1: GetDeviceInfo(&info); nuclear@1: // if strlen(info.DisplayDeviceName) == 0 then nuclear@1: // this HMD is 'fake' (created using sensor). nuclear@1: return (strlen(info.DisplayDeviceName) == 0); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: } // namespace OVR nuclear@1: