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
|