oculus1

view libovr/Src/linux/OVR_Linux_DeviceManager.cpp @ 24:8419d8a13cee

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 04 Oct 2013 14:50:26 +0300
parents
children
line source
1 /************************************************************************************
3 Filename : OVR_Linux_DeviceManager.h
4 Content : Linux implementation of DeviceManager.
5 Created :
6 Authors :
8 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
10 Use of this software is subject to the terms of the Oculus license
11 agreement provided at the time of installation or download, or which
12 otherwise accompanies this software in either electronic or hard copy form.
14 *************************************************************************************/
16 #include "OVR_Linux_DeviceManager.h"
18 // Sensor & HMD Factories
19 #include "OVR_LatencyTestImpl.h"
20 #include "OVR_SensorImpl.h"
21 #include "OVR_Linux_HIDDevice.h"
22 #include "OVR_Linux_HMDDevice.h"
24 #include "Kernel/OVR_Timer.h"
25 #include "Kernel/OVR_Std.h"
26 #include "Kernel/OVR_Log.h"
28 namespace OVR { namespace Linux {
31 //-------------------------------------------------------------------------------------
32 // **** Linux::DeviceManager
34 DeviceManager::DeviceManager()
35 {
36 }
38 DeviceManager::~DeviceManager()
39 {
40 }
42 bool DeviceManager::Initialize(DeviceBase*)
43 {
44 if (!DeviceManagerImpl::Initialize(0))
45 return false;
47 pThread = *new DeviceManagerThread();
48 if (!pThread || !pThread->Start())
49 return false;
51 // Wait for the thread to be fully up and running.
52 pThread->StartupEvent.Wait();
54 // Do this now that we know the thread's run loop.
55 HidDeviceManager = *HIDDeviceManager::CreateInternal(this);
57 pCreateDesc->pDevice = this;
58 LogText("OVR::DeviceManager - initialized.\n");
59 return true;
60 }
62 void DeviceManager::Shutdown()
63 {
64 LogText("OVR::DeviceManager - shutting down.\n");
66 // Set Manager shutdown marker variable; this prevents
67 // any existing DeviceHandle objects from accessing device.
68 pCreateDesc->pLock->pManager = 0;
70 // Push for thread shutdown *WITH NO WAIT*.
71 // This will have the following effect:
72 // - Exit command will get enqueued, which will be executed later on the thread itself.
73 // - Beyond this point, this DeviceManager object may be deleted by our caller.
74 // - Other commands, such as CreateDevice, may execute before ExitCommand, but they will
75 // fail gracefully due to pLock->pManager == 0. Future commands can't be enqued
76 // after pManager is null.
77 // - Once ExitCommand executes, ThreadCommand::Run loop will exit and release the last
78 // reference to the thread object.
79 pThread->PushExitCommand(false);
80 pThread.Clear();
82 DeviceManagerImpl::Shutdown();
83 }
85 ThreadCommandQueue* DeviceManager::GetThreadQueue()
86 {
87 return pThread;
88 }
90 ThreadId DeviceManager::GetThreadId() const
91 {
92 return pThread->GetThreadId();
93 }
95 bool DeviceManager::GetDeviceInfo(DeviceInfo* info) const
96 {
97 if ((info->InfoClassType != Device_Manager) &&
98 (info->InfoClassType != Device_None))
99 return false;
101 info->Type = Device_Manager;
102 info->Version = 0;
103 OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, "DeviceManager");
104 OVR_strcpy(info->Manufacturer,DeviceInfo::MaxNameLength, "Oculus VR, Inc.");
105 return true;
106 }
108 DeviceEnumerator<> DeviceManager::EnumerateDevicesEx(const DeviceEnumerationArgs& args)
109 {
110 // TBD: Can this be avoided in the future, once proper device notification is in place?
111 pThread->PushCall((DeviceManagerImpl*)this,
112 &DeviceManager::EnumerateAllFactoryDevices, true);
114 return DeviceManagerImpl::EnumerateDevicesEx(args);
115 }
118 //-------------------------------------------------------------------------------------
119 // ***** DeviceManager Thread
121 DeviceManagerThread::DeviceManagerThread()
122 : Thread(ThreadStackSize)
123 {
124 int result = pipe(CommandFd);
125 OVR_ASSERT(!result);
127 AddSelectFd(NULL, CommandFd[0]);
128 }
130 DeviceManagerThread::~DeviceManagerThread()
131 {
132 if (CommandFd[0])
133 {
134 RemoveSelectFd(NULL, CommandFd[0]);
135 close(CommandFd[0]);
136 close(CommandFd[1]);
137 }
138 }
140 bool DeviceManagerThread::AddSelectFd(Notifier* notify, int fd)
141 {
142 struct pollfd pfd;
143 pfd.fd = fd;
144 pfd.events = POLLIN|POLLHUP|POLLERR;
145 pfd.revents = 0;
147 FdNotifiers.PushBack(notify);
148 PollFds.PushBack(pfd);
150 OVR_ASSERT(FdNotifiers.GetSize() == PollFds.GetSize());
151 return true;
152 }
154 bool DeviceManagerThread::RemoveSelectFd(Notifier* notify, int fd)
155 {
156 // [0] is reserved for thread commands with notify of null, but we still
157 // can use this function to remove it.
158 for (UPInt i = 0; i < FdNotifiers.GetSize(); i++)
159 {
160 if ((FdNotifiers[i] == notify) && (PollFds[i].fd == fd))
161 {
162 FdNotifiers.RemoveAt(i);
163 PollFds.RemoveAt(i);
164 return true;
165 }
166 }
167 return false;
168 }
172 int DeviceManagerThread::Run()
173 {
174 ThreadCommand::PopBuffer command;
176 SetThreadName("OVR::DeviceManagerThread");
177 LogText("OVR::DeviceManagerThread - running (ThreadId=%p).\n", GetThreadId());
179 // Signal to the parent thread that initialization has finished.
180 StartupEvent.SetEvent();
182 while(!IsExiting())
183 {
184 // PopCommand will reset event on empty queue.
185 if (PopCommand(&command))
186 {
187 command.Execute();
188 }
189 else
190 {
191 bool commands = 0;
192 do
193 {
194 int waitMs = -1;
196 // If devices have time-dependent logic registered, get the longest wait
197 // allowed based on current ticks.
198 if (!TicksNotifiers.IsEmpty())
199 {
200 UInt64 ticksMks = Timer::GetTicks();
201 int waitAllowed;
203 for (UPInt j = 0; j < TicksNotifiers.GetSize(); j++)
204 {
205 waitAllowed = (int)(TicksNotifiers[j]->OnTicks(ticksMks) / Timer::MksPerMs);
206 if (waitAllowed < waitMs)
207 waitMs = waitAllowed;
208 }
209 }
211 // wait until there is data available on one of the devices or the timeout expires
212 int n = poll(&PollFds[0], PollFds.GetSize(), waitMs);
214 if (n > 0)
215 {
216 // Iterate backwards through the list so the ordering will not be
217 // affected if the called object gets removed during the callback
218 // Also, the HID data streams are located toward the back of the list
219 // and servicing them first will allow a disconnect to be handled
220 // and cleaned directly at the device first instead of the general HID monitor
221 for (int i=PollFds.GetSize()-1; i>=0; i--)
222 {
223 if (PollFds[i].revents & POLLERR)
224 {
225 OVR_DEBUG_LOG(("poll: error on [%d]: %d", i, PollFds[i].fd));
226 }
227 else if (PollFds[i].revents & POLLIN)
228 {
229 if (FdNotifiers[i])
230 FdNotifiers[i]->OnEvent(i, PollFds[i].fd);
231 else if (i == 0) // command
232 {
233 char dummy[128];
234 read(PollFds[i].fd, dummy, 128);
235 commands = 1;
236 }
237 }
239 if (PollFds[i].revents & POLLHUP)
240 PollFds[i].events = 0;
242 if (PollFds[i].revents != 0)
243 {
244 n--;
245 if (n == 0)
246 break;
247 }
248 }
249 }
250 } while (PollFds.GetSize() > 0 && !commands);
251 }
252 }
254 LogText("OVR::DeviceManagerThread - exiting (ThreadId=%p).\n", GetThreadId());
255 return 0;
256 }
258 bool DeviceManagerThread::AddTicksNotifier(Notifier* notify)
259 {
260 TicksNotifiers.PushBack(notify);
261 return true;
262 }
264 bool DeviceManagerThread::RemoveTicksNotifier(Notifier* notify)
265 {
266 for (UPInt i = 0; i < TicksNotifiers.GetSize(); i++)
267 {
268 if (TicksNotifiers[i] == notify)
269 {
270 TicksNotifiers.RemoveAt(i);
271 return true;
272 }
273 }
274 return false;
275 }
277 } // namespace Linux
280 //-------------------------------------------------------------------------------------
281 // ***** Creation
284 // Creates a new DeviceManager and initializes OVR.
285 DeviceManager* DeviceManager::Create()
286 {
287 if (!System::IsInitialized())
288 {
289 // Use custom message, since Log is not yet installed.
290 OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
291 LogMessage(Log_Debug, "DeviceManager::Create failed - OVR::System not initialized"); );
292 return 0;
293 }
295 Ptr<Linux::DeviceManager> manager = *new Linux::DeviceManager;
297 if (manager)
298 {
299 if (manager->Initialize(0))
300 {
301 manager->AddFactory(&LatencyTestDeviceFactory::Instance);
302 manager->AddFactory(&SensorDeviceFactory::Instance);
303 manager->AddFactory(&Linux::HMDDeviceFactory::Instance);
305 manager->AddRef();
306 }
307 else
308 {
309 manager.Clear();
310 }
312 }
314 return manager.GetPtr();
315 }
318 } // namespace OVR