oculus1

annotate libovr/Src/OVR_DeviceImpl.h @ 23:0c76f70fb7e9

merged
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 28 Sep 2013 04:13:33 +0300
parents
children
rev   line source
nuclear@1 1 /************************************************************************************
nuclear@1 2
nuclear@1 3 Filename : OVR_DeviceImpl.h
nuclear@1 4 Content : Partial back-end independent implementation of Device interfaces
nuclear@1 5 Created : October 10, 2012
nuclear@1 6 Authors : Michael Antonov
nuclear@1 7
nuclear@1 8 Copyright : Copyright 2012 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 #ifndef OVR_DeviceImpl_h
nuclear@1 17 #define OVR_DeviceImpl_h
nuclear@1 18
nuclear@1 19 #include "OVR_Device.h"
nuclear@1 20 #include "Kernel/OVR_Atomic.h"
nuclear@1 21 #include "Kernel/OVR_Log.h"
nuclear@1 22 #include "Kernel/OVR_System.h"
nuclear@1 23
nuclear@1 24 #include "Kernel/OVR_Threads.h"
nuclear@1 25 #include "OVR_ThreadCommandQueue.h"
nuclear@1 26 #include "OVR_HIDDevice.h"
nuclear@1 27
nuclear@1 28 namespace OVR {
nuclear@1 29
nuclear@1 30 class DeviceManagerImpl;
nuclear@1 31 class DeviceFactory;
nuclear@1 32
nuclear@1 33 enum
nuclear@1 34 {
nuclear@1 35 Oculus_VendorId = 0x2833
nuclear@1 36 };
nuclear@1 37
nuclear@1 38 //-------------------------------------------------------------------------------------
nuclear@1 39 // Globally shared Lock implementation used for MessageHandlers.
nuclear@1 40
nuclear@1 41 class SharedLock
nuclear@1 42 {
nuclear@1 43 public:
nuclear@1 44 SharedLock() : UseCount(0) {}
nuclear@1 45
nuclear@1 46 Lock* GetLockAddRef();
nuclear@1 47 void ReleaseLock(Lock* plock);
nuclear@1 48
nuclear@1 49 private:
nuclear@1 50 Lock* toLock() { return (Lock*)Buffer; }
nuclear@1 51
nuclear@1 52 // UseCount and max alignment.
nuclear@1 53 volatile int UseCount;
nuclear@1 54 UInt64 Buffer[(sizeof(Lock)+sizeof(UInt64)-1)/sizeof(UInt64)];
nuclear@1 55 };
nuclear@1 56
nuclear@1 57
nuclear@1 58 // Wrapper for MessageHandler that includes synchronization logic.
nuclear@1 59 // References to MessageHandlers are organized in a list to allow for them to
nuclear@1 60 // easily removed with MessageHandler::RemoveAllHandlers.
nuclear@1 61 class MessageHandlerRef : public ListNode<MessageHandlerRef>
nuclear@1 62 {
nuclear@1 63 public:
nuclear@1 64 MessageHandlerRef(DeviceBase* device);
nuclear@1 65 ~MessageHandlerRef();
nuclear@1 66
nuclear@1 67 void SetHandler(MessageHandler* hander);
nuclear@1 68
nuclear@1 69 // Not-thread-safe version
nuclear@1 70 void SetHandler_NTS(MessageHandler* hander);
nuclear@1 71
nuclear@1 72 void Call(const Message& msg)
nuclear@1 73 {
nuclear@1 74 Lock::Locker lockScope(pLock);
nuclear@1 75 if (pHandler)
nuclear@1 76 pHandler->OnMessage(msg);
nuclear@1 77 }
nuclear@1 78
nuclear@1 79 Lock* GetLock() const { return pLock; }
nuclear@1 80
nuclear@1 81 // GetHandler() is not thread safe if used out of order across threads; nothing can be done
nuclear@1 82 // about that.
nuclear@1 83 MessageHandler* GetHandler() const { return pHandler; }
nuclear@1 84 DeviceBase* GetDevice() const { return pDevice; }
nuclear@1 85
nuclear@1 86 private:
nuclear@1 87 Lock* pLock; // Cached global handler lock.
nuclear@1 88 DeviceBase* pDevice;
nuclear@1 89 MessageHandler* pHandler;
nuclear@1 90 };
nuclear@1 91
nuclear@1 92
nuclear@1 93
nuclear@1 94 //-------------------------------------------------------------------------------------
nuclear@1 95
nuclear@1 96 // DeviceManagerLock is a synchronization lock used by DeviceManager for Devices
nuclear@1 97 // and is allocated separately for potentially longer lifetime.
nuclear@1 98 //
nuclear@1 99 // DeviceManagerLock is used for all of the following:
nuclear@1 100 // - Adding/removing devices
nuclear@1 101 // - Reporting manager lifetime (pManager != 0) for DeviceHandles
nuclear@1 102 // - Protecting device creation/shutdown.
nuclear@1 103
nuclear@1 104 class DeviceManagerLock : public RefCountBase<DeviceManagerLock>
nuclear@1 105 {
nuclear@1 106 public:
nuclear@1 107 Lock CreateLock;
nuclear@1 108 DeviceManagerImpl* pManager;
nuclear@1 109
nuclear@1 110 DeviceManagerLock() : pManager(0) { }
nuclear@1 111 };
nuclear@1 112
nuclear@1 113
nuclear@1 114 // DeviceCreateDesc provides all of the information needed to create any device, a derived
nuclear@1 115 // instance of this class is created by DeviceFactory during enumeration.
nuclear@1 116 // - DeviceCreateDesc may or may not be a part of DeviceManager::Devices list (check pNext != 0).
nuclear@1 117 // - Referenced and kept alive by DeviceHandle.
nuclear@1 118
nuclear@1 119 class DeviceCreateDesc : public ListNode<DeviceCreateDesc>, public NewOverrideBase
nuclear@1 120 {
nuclear@1 121 void operator = (const DeviceCreateDesc&) { } // Assign not supported; suppress MSVC warning.
nuclear@1 122 public:
nuclear@1 123 DeviceCreateDesc(DeviceFactory* factory, DeviceType type)
nuclear@1 124 : pFactory(factory), Type(type), pLock(0), HandleCount(0), pDevice(0), Enumerated(true)
nuclear@1 125 {
nuclear@1 126 pNext = pPrev = 0;
nuclear@1 127 }
nuclear@1 128
nuclear@1 129 virtual ~DeviceCreateDesc()
nuclear@1 130 {
nuclear@1 131 OVR_ASSERT(!pDevice);
nuclear@1 132 if (pNext)
nuclear@1 133 RemoveNode();
nuclear@1 134 }
nuclear@1 135
nuclear@1 136 DeviceManagerImpl* GetManagerImpl() const { return pLock->pManager; }
nuclear@1 137 Lock* GetLock() const { return &pLock->CreateLock; }
nuclear@1 138
nuclear@1 139 // DeviceCreateDesc reference counting is tied to Devices list management,
nuclear@1 140 // see comments for HandleCount.
nuclear@1 141 void AddRef();
nuclear@1 142 void Release();
nuclear@1 143
nuclear@1 144
nuclear@1 145 // *** Device creation/matching Interface
nuclear@1 146
nuclear@1 147
nuclear@1 148 // Cloning copies us to an allocated object when new device is enumerated.
nuclear@1 149 virtual DeviceCreateDesc* Clone() const = 0;
nuclear@1 150 // Creates a new device instance without Initializing it; the
nuclear@1 151 // later is done my Initialize()/Shutdown() methods of the device itself.
nuclear@1 152 virtual DeviceBase* NewDeviceInstance() = 0;
nuclear@1 153 // Override to return device-specific info.
nuclear@1 154 virtual bool GetDeviceInfo(DeviceInfo* info) const = 0;
nuclear@1 155
nuclear@1 156
nuclear@1 157 enum MatchResult
nuclear@1 158 {
nuclear@1 159 Match_None,
nuclear@1 160 Match_Found,
nuclear@1 161 Match_Candidate
nuclear@1 162 };
nuclear@1 163
nuclear@1 164 // Override to return Match_Found if descriptor matches our device.
nuclear@1 165 // Match_Candidate can be returned, with pcandicate update, if this may be a match
nuclear@1 166 // but more searching is necessary. If this is the case UpdateMatchedCandidate will be called.
nuclear@1 167 virtual MatchResult MatchDevice(const DeviceCreateDesc& other,
nuclear@1 168 DeviceCreateDesc** pcandidate) const = 0;
nuclear@1 169
nuclear@1 170 // Called for matched candidate after all potential matches are iterated.
nuclear@1 171 // Used to update HMDevice creation arguments from Sensor.
nuclear@1 172 // Optional return param 'newDeviceFlag' will be set to true if the
nuclear@1 173 // 'desc' refers to a new device; false, otherwise.
nuclear@1 174 // Return 'false' to create new object, 'true' if done with this argument.
nuclear@1 175 virtual bool UpdateMatchedCandidate(
nuclear@1 176 const DeviceCreateDesc& desc, bool* newDeviceFlag = NULL)
nuclear@1 177 { OVR_UNUSED2(desc, newDeviceFlag); return false; }
nuclear@1 178
nuclear@1 179 // Matches HID device to the descriptor.
nuclear@1 180 virtual bool MatchHIDDevice(const HIDDeviceDesc&) const { return false; }
nuclear@1 181
nuclear@1 182 // Matches device by path.
nuclear@1 183 virtual bool MatchDevice(const String& /*path*/) { return false; }
nuclear@1 184 //protected:
nuclear@1 185 DeviceFactory* const pFactory;
nuclear@1 186 const DeviceType Type;
nuclear@1 187
nuclear@1 188 // List in which this descriptor lives. pList->CreateLock required if added/removed.
nuclear@1 189 Ptr<DeviceManagerLock> pLock;
nuclear@1 190
nuclear@1 191 // Strong references to us: Incremented by Device, DeviceHandles & Enumerators.
nuclear@1 192 // May be 0 if device not created and there are no handles.
nuclear@1 193 // Following transitions require pList->CreateLock:
nuclear@1 194 // {1 -> 0}: May delete & remove handle if no longer available.
nuclear@1 195 // {0 -> 1}: Device creation is only possible if manager is still alive.
nuclear@1 196 AtomicInt<UInt32> HandleCount;
nuclear@1 197 // If not null, points to our created device instance. Modified during lock only.
nuclear@1 198 DeviceBase* pDevice;
nuclear@1 199 // True if device is marked as available during enumeration.
nuclear@1 200 bool Enumerated;
nuclear@1 201 };
nuclear@1 202
nuclear@1 203
nuclear@1 204
nuclear@1 205 // Common data present in the implementation of every DeviceBase.
nuclear@1 206 // Injected by DeviceImpl.
nuclear@1 207 class DeviceCommon
nuclear@1 208 {
nuclear@1 209 public:
nuclear@1 210 AtomicInt<UInt32> RefCount;
nuclear@1 211 Ptr<DeviceCreateDesc> pCreateDesc;
nuclear@1 212 Ptr<DeviceBase> pParent;
nuclear@1 213 MessageHandlerRef HandlerRef;
nuclear@1 214
nuclear@1 215 DeviceCommon(DeviceCreateDesc* createDesc, DeviceBase* device, DeviceBase* parent)
nuclear@1 216 : RefCount(1), pCreateDesc(createDesc), pParent(parent), HandlerRef(device)
nuclear@1 217 {
nuclear@1 218 }
nuclear@1 219
nuclear@1 220 // Device reference counting delegates to Manager thread to actually kill devices.
nuclear@1 221 void DeviceAddRef();
nuclear@1 222 void DeviceRelease();
nuclear@1 223
nuclear@1 224 Lock* GetLock() const { return pCreateDesc->GetLock(); }
nuclear@1 225
nuclear@1 226 virtual bool Initialize(DeviceBase* parent) = 0;
nuclear@1 227 virtual void Shutdown() = 0;
nuclear@1 228 };
nuclear@1 229
nuclear@1 230
nuclear@1 231 //-------------------------------------------------------------------------------------
nuclear@1 232 // DeviceImpl address DeviceRecord implementation to a device base class B.
nuclear@1 233 // B must be derived form DeviceBase.
nuclear@1 234
nuclear@1 235 template<class B>
nuclear@1 236 class DeviceImpl : public B, public DeviceCommon
nuclear@1 237 {
nuclear@1 238 public:
nuclear@1 239 DeviceImpl(DeviceCreateDesc* createDesc, DeviceBase* parent)
nuclear@1 240 : DeviceCommon(createDesc, getThis(), parent)
nuclear@1 241 {
nuclear@1 242 }
nuclear@1 243
nuclear@1 244 // Convenience method to avoid manager access typecasts.
nuclear@1 245 DeviceManagerImpl* GetManagerImpl() const { return pCreateDesc->pLock->pManager; }
nuclear@1 246
nuclear@1 247 // Inline to avoid warnings.
nuclear@1 248 DeviceImpl* getThis() { return this; }
nuclear@1 249
nuclear@1 250 // Common implementation delegate to avoid virtual inheritance and dynamic casts.
nuclear@1 251 virtual DeviceCommon* getDeviceCommon() const { return (DeviceCommon*)this; }
nuclear@1 252
nuclear@1 253 /*
nuclear@1 254 virtual void AddRef() { pCreateDesc->DeviceAddRef(); }
nuclear@1 255 virtual void Release() { pCreateDesc->DeviceRelease(); }
nuclear@1 256 virtual DeviceBase* GetParent() const { return pParent.GetPtr(); }
nuclear@1 257 virtual DeviceManager* GetManager() const { return pCreateDesc->pLock->pManager;}
nuclear@1 258 virtual void SetMessageHandler(MessageHandler* handler) { HanderRef.SetHandler(handler); }
nuclear@1 259 virtual MessageHandler* GetMessageHandler() const { return HanderRef.GetHandler(); }
nuclear@1 260 virtual DeviceType GetType() const { return pCreateDesc->Type; }
nuclear@1 261 virtual DeviceType GetType() const { return pCreateDesc->Type; }
nuclear@1 262 */
nuclear@1 263 };
nuclear@1 264
nuclear@1 265
nuclear@1 266 //-------------------------------------------------------------------------------------
nuclear@1 267 // ***** DeviceFactory
nuclear@1 268
nuclear@1 269 // DeviceFactory is maintained in DeviceManager for each separately-enumerable
nuclear@1 270 // device type; factories allow separation of unrelated enumeration code.
nuclear@1 271
nuclear@1 272 class DeviceFactory : public ListNode<DeviceFactory>, public NewOverrideBase
nuclear@1 273 {
nuclear@1 274 public:
nuclear@1 275
nuclear@1 276 DeviceFactory() : pManager(0)
nuclear@1 277 {
nuclear@1 278 pNext = pPrev = 0;
nuclear@1 279 }
nuclear@1 280 virtual ~DeviceFactory() { }
nuclear@1 281
nuclear@1 282 DeviceManagerImpl* GetManagerImpl() { return pManager; }
nuclear@1 283
nuclear@1 284 // Notifiers called when we are added to/removed from a device.
nuclear@1 285 virtual bool AddedToManager(DeviceManagerImpl* manager)
nuclear@1 286 {
nuclear@1 287 OVR_ASSERT(pManager == 0);
nuclear@1 288 pManager = manager;
nuclear@1 289 return true;
nuclear@1 290 }
nuclear@1 291
nuclear@1 292 virtual void RemovedFromManager()
nuclear@1 293 {
nuclear@1 294 pManager = 0;
nuclear@1 295 }
nuclear@1 296
nuclear@1 297
nuclear@1 298 // *** Device Enumeration/Creation Support
nuclear@1 299
nuclear@1 300 // Passed to EnumerateDevices to be informed of every device detected.
nuclear@1 301 class EnumerateVisitor
nuclear@1 302 {
nuclear@1 303 public:
nuclear@1 304 virtual void Visit(const DeviceCreateDesc& createDesc) = 0;
nuclear@1 305 };
nuclear@1 306
nuclear@1 307 // Enumerates factory devices by notifying EnumerateVisitor about every
nuclear@1 308 // device that is present.
nuclear@1 309 virtual void EnumerateDevices(EnumerateVisitor& visitor) = 0;
nuclear@1 310
nuclear@1 311 // Matches vendorId/productId pair with the factory; returns 'true'
nuclear@1 312 // if the factory can handle the device.
nuclear@1 313 virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId) const
nuclear@1 314 {
nuclear@1 315 OVR_UNUSED2(vendorId, productId);
nuclear@1 316 return false;
nuclear@1 317 }
nuclear@1 318
nuclear@1 319 // Detects the HID device and adds the DeviceCreateDesc into Devices list, if
nuclear@1 320 // the device belongs to this factory. Returns 'false', if not.
nuclear@1 321 virtual bool DetectHIDDevice(DeviceManager* pdevMgr, const HIDDeviceDesc& desc)
nuclear@1 322 {
nuclear@1 323 OVR_UNUSED2(pdevMgr, desc);
nuclear@1 324 return false;
nuclear@1 325 }
nuclear@1 326
nuclear@1 327 protected:
nuclear@1 328 DeviceManagerImpl* pManager;
nuclear@1 329 };
nuclear@1 330
nuclear@1 331
nuclear@1 332 //-------------------------------------------------------------------------------------
nuclear@1 333 // ***** DeviceManagerImpl
nuclear@1 334
nuclear@1 335 // DeviceManagerImpl is a partial default DeviceManager implementation that
nuclear@1 336 // maintains a list of devices and supports their enumeration.
nuclear@1 337
nuclear@1 338 class DeviceManagerImpl : public DeviceImpl<OVR::DeviceManager>, public ThreadCommandQueue
nuclear@1 339 {
nuclear@1 340 public:
nuclear@1 341 DeviceManagerImpl();
nuclear@1 342 ~DeviceManagerImpl();
nuclear@1 343
nuclear@1 344 // Constructor helper function to create Descriptor and manager lock during initialization.
nuclear@1 345 static DeviceCreateDesc* CreateManagerDesc();
nuclear@1 346
nuclear@1 347 // DeviceManagerImpl provides partial implementation of Initialize/Shutdown that must
nuclear@1 348 // be called by the platform-specific derived class.
nuclear@1 349 virtual bool Initialize(DeviceBase* parent);
nuclear@1 350 virtual void Shutdown();
nuclear@1 351
nuclear@1 352
nuclear@1 353 // Every DeviceManager has an associated profile manager, which is used to store
nuclear@1 354 // user settings that may affect device behavior.
nuclear@1 355 virtual ProfileManager* GetProfileManager() const { return pProfileManager.GetPtr(); }
nuclear@1 356
nuclear@1 357 // Override to return ThreadCommandQueue implementation used to post commands
nuclear@1 358 // to the background device manager thread (that must be created by Initialize).
nuclear@1 359 virtual ThreadCommandQueue* GetThreadQueue() = 0;
nuclear@1 360
nuclear@1 361 // Returns the thread id of the DeviceManager.
nuclear@1 362 virtual ThreadId GetThreadId() const = 0;
nuclear@1 363
nuclear@1 364 virtual DeviceEnumerator<> EnumerateDevicesEx(const DeviceEnumerationArgs& args);
nuclear@1 365
nuclear@1 366
nuclear@1 367 //
nuclear@1 368 void AddFactory(DeviceFactory* factory)
nuclear@1 369 {
nuclear@1 370 // This lock is only needed if we call AddFactory after manager thread creation.
nuclear@1 371 Lock::Locker scopeLock(GetLock());
nuclear@1 372 Factories.PushBack(factory);
nuclear@1 373 factory->AddedToManager(this);
nuclear@1 374 }
nuclear@1 375
nuclear@1 376 void CallOnDeviceAdded(DeviceCreateDesc* desc)
nuclear@1 377 {
nuclear@1 378 HandlerRef.Call(MessageDeviceStatus(Message_DeviceAdded, this, DeviceHandle(desc)));
nuclear@1 379 }
nuclear@1 380 void CallOnDeviceRemoved(DeviceCreateDesc* desc)
nuclear@1 381 {
nuclear@1 382 HandlerRef.Call(MessageDeviceStatus(Message_DeviceRemoved, this, DeviceHandle(desc)));
nuclear@1 383 }
nuclear@1 384
nuclear@1 385 // Helper to access Common data for a device.
nuclear@1 386 static DeviceCommon* GetDeviceCommon(DeviceBase* device)
nuclear@1 387 {
nuclear@1 388 return device->getDeviceCommon();
nuclear@1 389 }
nuclear@1 390
nuclear@1 391
nuclear@1 392 // Background-thread callbacks for DeviceCreation/Release. These
nuclear@1 393 DeviceBase* CreateDevice_MgrThread(DeviceCreateDesc* createDesc, DeviceBase* parent = 0);
nuclear@1 394 Void ReleaseDevice_MgrThread(DeviceBase* device);
nuclear@1 395
nuclear@1 396
nuclear@1 397 // Calls EnumerateDevices() on all factories
nuclear@1 398 virtual Void EnumerateAllFactoryDevices();
nuclear@1 399 // Enumerates devices for a particular factory.
nuclear@1 400 virtual Void EnumerateFactoryDevices(DeviceFactory* factory);
nuclear@1 401
nuclear@1 402 virtual HIDDeviceManager* GetHIDDeviceManager() const
nuclear@1 403 {
nuclear@1 404 return HidDeviceManager;
nuclear@1 405 }
nuclear@1 406
nuclear@1 407 // Adds device (DeviceCreateDesc*) into Devices. Returns NULL,
nuclear@1 408 // if unsuccessful or device is already in the list.
nuclear@1 409 virtual Ptr<DeviceCreateDesc> AddDevice_NeedsLock(const DeviceCreateDesc& createDesc);
nuclear@1 410
nuclear@1 411 // Finds a device descriptor by path and optional type.
nuclear@1 412 Ptr<DeviceCreateDesc> FindDevice(const String& path, DeviceType = Device_None);
nuclear@1 413
nuclear@1 414 // Finds HID device by HIDDeviceDesc.
nuclear@1 415 Ptr<DeviceCreateDesc> FindHIDDevice(const HIDDeviceDesc&);
nuclear@1 416 void DetectHIDDevice(const HIDDeviceDesc&);
nuclear@1 417
nuclear@1 418 // Manager Lock-protected list of devices.
nuclear@1 419 List<DeviceCreateDesc> Devices;
nuclear@1 420
nuclear@1 421 // Factories used to detect and manage devices.
nuclear@1 422 List<DeviceFactory> Factories;
nuclear@1 423
nuclear@1 424 protected:
nuclear@1 425 Ptr<HIDDeviceManager> HidDeviceManager;
nuclear@1 426 Ptr<ProfileManager> pProfileManager;
nuclear@1 427 };
nuclear@1 428
nuclear@1 429
nuclear@1 430 } // namespace OVR
nuclear@1 431
nuclear@1 432 #endif