oculus1
diff libovr/Src/linux/OVR_Linux_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/linux/OVR_Linux_HIDDevice.cpp Sat Sep 14 16:14:59 2013 +0300 1.3 @@ -0,0 +1,799 @@ 1.4 +/************************************************************************************ 1.5 +Filename : OVR_Linux_HIDDevice.cpp 1.6 +Content : Linux 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_Linux_HIDDevice.h" 1.19 + 1.20 +#include <sys/ioctl.h> 1.21 +#include <fcntl.h> 1.22 +#include <errno.h> 1.23 +#include <linux/hidraw.h> 1.24 +#include "OVR_HIDDeviceImpl.h" 1.25 + 1.26 +namespace OVR { namespace Linux { 1.27 + 1.28 +static const UInt32 MAX_QUEUED_INPUT_REPORTS = 5; 1.29 + 1.30 +//------------------------------------------------------------------------------------- 1.31 +// **** Linux::DeviceManager 1.32 +//----------------------------------------------------------------------------- 1.33 +HIDDeviceManager::HIDDeviceManager(DeviceManager* manager) : DevManager(manager) 1.34 +{ 1.35 + UdevInstance = NULL; 1.36 + HIDMonitor = NULL; 1.37 + HIDMonHandle = -1; 1.38 +} 1.39 + 1.40 +//----------------------------------------------------------------------------- 1.41 +HIDDeviceManager::~HIDDeviceManager() 1.42 +{ 1.43 +} 1.44 + 1.45 +//----------------------------------------------------------------------------- 1.46 +bool HIDDeviceManager::initializeManager() 1.47 +{ 1.48 + if (HIDMonitor) 1.49 + { 1.50 + return true; 1.51 + } 1.52 + 1.53 + // Create a udev_monitor handle to watch for device changes (hot-plug detection) 1.54 + HIDMonitor = udev_monitor_new_from_netlink(UdevInstance, "udev"); 1.55 + if (HIDMonitor == NULL) 1.56 + { 1.57 + return false; 1.58 + } 1.59 + 1.60 + udev_monitor_filter_add_match_subsystem_devtype(HIDMonitor, "hidraw", NULL); // filter for hidraw only 1.61 + 1.62 + int err = udev_monitor_enable_receiving(HIDMonitor); 1.63 + if (err) 1.64 + { 1.65 + udev_monitor_unref(HIDMonitor); 1.66 + HIDMonitor = NULL; 1.67 + return false; 1.68 + } 1.69 + 1.70 + // Get the file descriptor (fd) for the monitor. 1.71 + HIDMonHandle = udev_monitor_get_fd(HIDMonitor); 1.72 + if (HIDMonHandle < 0) 1.73 + { 1.74 + udev_monitor_unref(HIDMonitor); 1.75 + HIDMonitor = NULL; 1.76 + return false; 1.77 + } 1.78 + 1.79 + // This file handle will be polled along-side with the device hid handles for changes 1.80 + // Add the handle to the polling list 1.81 + if (!DevManager->pThread->AddSelectFd(this, HIDMonHandle)) 1.82 + { 1.83 + close(HIDMonHandle); 1.84 + HIDMonHandle = -1; 1.85 + 1.86 + udev_monitor_unref(HIDMonitor); 1.87 + HIDMonitor = NULL; 1.88 + return false; 1.89 + } 1.90 + 1.91 + return true; 1.92 +} 1.93 + 1.94 +//----------------------------------------------------------------------------- 1.95 +bool HIDDeviceManager::Initialize() 1.96 +{ 1.97 + // Get a udev library handle. This handle must stay active during the 1.98 + // duration the lifetime of device monitoring handles 1.99 + UdevInstance = udev_new(); 1.100 + if (!UdevInstance) 1.101 + return false; 1.102 + 1.103 + return initializeManager(); 1.104 +} 1.105 + 1.106 +//----------------------------------------------------------------------------- 1.107 +void HIDDeviceManager::Shutdown() 1.108 +{ 1.109 + OVR_ASSERT_LOG((UdevInstance), ("Should have called 'Initialize' before 'Shutdown'.")); 1.110 + 1.111 + if (HIDMonitor) 1.112 + { 1.113 + DevManager->pThread->RemoveSelectFd(this, HIDMonHandle); 1.114 + close(HIDMonHandle); 1.115 + HIDMonHandle = -1; 1.116 + 1.117 + udev_monitor_unref(HIDMonitor); 1.118 + HIDMonitor = NULL; 1.119 + } 1.120 + 1.121 + udev_unref(UdevInstance); // release the library 1.122 + 1.123 + LogText("OVR::Linux::HIDDeviceManager - shutting down.\n"); 1.124 +} 1.125 + 1.126 +//------------------------------------------------------------------------------- 1.127 +bool HIDDeviceManager::AddNotificationDevice(HIDDevice* device) 1.128 +{ 1.129 + NotificationDevices.PushBack(device); 1.130 + return true; 1.131 +} 1.132 + 1.133 +//------------------------------------------------------------------------------- 1.134 +bool HIDDeviceManager::RemoveNotificationDevice(HIDDevice* device) 1.135 +{ 1.136 + for (UPInt i = 0; i < NotificationDevices.GetSize(); i++) 1.137 + { 1.138 + if (NotificationDevices[i] == device) 1.139 + { 1.140 + NotificationDevices.RemoveAt(i); 1.141 + return true; 1.142 + } 1.143 + } 1.144 + return false; 1.145 +} 1.146 + 1.147 +//----------------------------------------------------------------------------- 1.148 +bool HIDDeviceManager::getIntProperty(udev_device* device, 1.149 + const char* propertyName, 1.150 + SInt32* pResult) 1.151 +{ 1.152 + const char* str = udev_device_get_sysattr_value(device, propertyName); 1.153 + if (str) 1.154 + { 1.155 + *pResult = strtol(str, NULL, 16); 1.156 + return true; 1.157 + } 1.158 + else 1.159 + { 1.160 + *pResult = 0; 1.161 + return true; 1.162 + } 1.163 +} 1.164 + 1.165 +//----------------------------------------------------------------------------- 1.166 +bool HIDDeviceManager::initVendorProductVersion(udev_device* device, HIDDeviceDesc* pDevDesc) 1.167 +{ 1.168 + SInt32 result; 1.169 + if (getIntProperty(device, "idVendor", &result)) 1.170 + pDevDesc->VendorId = result; 1.171 + else 1.172 + return false; 1.173 + 1.174 + if (getIntProperty(device, "idProduct", &result)) 1.175 + pDevDesc->ProductId = result; 1.176 + else 1.177 + return false; 1.178 + 1.179 + return true; 1.180 +} 1.181 + 1.182 +//----------------------------------------------------------------------------- 1.183 +bool HIDDeviceManager::getStringProperty(udev_device* device, 1.184 + const char* propertyName, 1.185 + OVR::String* pResult) 1.186 +{ 1.187 + // Get the attribute in UTF8 1.188 + const char* str = udev_device_get_sysattr_value(device, propertyName); 1.189 + if (str) 1.190 + { // Copy the string into the return value 1.191 + *pResult = String(str); 1.192 + return true; 1.193 + } 1.194 + else 1.195 + { 1.196 + return false; 1.197 + } 1.198 +} 1.199 + 1.200 +//----------------------------------------------------------------------------- 1.201 +bool HIDDeviceManager::Enumerate(HIDEnumerateVisitor* enumVisitor) 1.202 +{ 1.203 + 1.204 + if (!initializeManager()) 1.205 + { 1.206 + return false; 1.207 + } 1.208 + 1.209 + // Get a list of hid devices 1.210 + udev_enumerate* devices = udev_enumerate_new(UdevInstance); 1.211 + udev_enumerate_add_match_subsystem(devices, "hidraw"); 1.212 + udev_enumerate_scan_devices(devices); 1.213 + 1.214 + udev_list_entry* entry = udev_enumerate_get_list_entry(devices); 1.215 + 1.216 + // Search each device for the matching vid/pid 1.217 + while (entry != NULL) 1.218 + { 1.219 + // Get the device file name 1.220 + const char* sysfs_path = udev_list_entry_get_name(entry); 1.221 + udev_device* hid; // The device's HID udev node. 1.222 + hid = udev_device_new_from_syspath(UdevInstance, sysfs_path); 1.223 + const char* dev_path = udev_device_get_devnode(hid); 1.224 + 1.225 + // Get the USB device 1.226 + hid = udev_device_get_parent_with_subsystem_devtype(hid, "usb", "usb_device"); 1.227 + if (hid) 1.228 + { 1.229 + HIDDeviceDesc devDesc; 1.230 + 1.231 + // Check the VID/PID for a match 1.232 + if (dev_path && 1.233 + initVendorProductVersion(hid, &devDesc) && 1.234 + enumVisitor->MatchVendorProduct(devDesc.VendorId, devDesc.ProductId)) 1.235 + { 1.236 + devDesc.Path = dev_path; 1.237 + getFullDesc(hid, &devDesc); 1.238 + 1.239 + // Look for the device to check if it is already opened. 1.240 + Ptr<DeviceCreateDesc> existingDevice = DevManager->FindHIDDevice(devDesc); 1.241 + // if device exists and it is opened then most likely the device open() 1.242 + // will fail; therefore, we just set Enumerated to 'true' and continue. 1.243 + if (existingDevice && existingDevice->pDevice) 1.244 + { 1.245 + existingDevice->Enumerated = true; 1.246 + } 1.247 + else 1.248 + { // open the device temporarily for startup communication 1.249 + int device_handle = open(dev_path, O_RDWR); 1.250 + if (device_handle >= 0) 1.251 + { 1.252 + // Construct minimal device that the visitor callback can get feature reports from 1.253 + Linux::HIDDevice device(this, device_handle); 1.254 + enumVisitor->Visit(device, devDesc); 1.255 + 1.256 + close(device_handle); // close the file handle 1.257 + } 1.258 + } 1.259 + } 1.260 + 1.261 + udev_device_unref(hid); 1.262 + entry = udev_list_entry_get_next(entry); 1.263 + } 1.264 + } 1.265 + 1.266 + // Free the enumerator and udev objects 1.267 + udev_enumerate_unref(devices); 1.268 + 1.269 + return true; 1.270 +} 1.271 + 1.272 +//----------------------------------------------------------------------------- 1.273 +OVR::HIDDevice* HIDDeviceManager::Open(const String& path) 1.274 +{ 1.275 + Ptr<Linux::HIDDevice> device = *new Linux::HIDDevice(this); 1.276 + 1.277 + if (device->HIDInitialize(path)) 1.278 + { 1.279 + device->AddRef(); 1.280 + return device; 1.281 + } 1.282 + 1.283 + return NULL; 1.284 +} 1.285 + 1.286 +//----------------------------------------------------------------------------- 1.287 +bool HIDDeviceManager::getFullDesc(udev_device* device, HIDDeviceDesc* desc) 1.288 +{ 1.289 + 1.290 + if (!initVendorProductVersion(device, desc)) 1.291 + { 1.292 + return false; 1.293 + } 1.294 + 1.295 + if (!getStringProperty(device, "serial", &(desc->SerialNumber))) 1.296 + { 1.297 + return false; 1.298 + } 1.299 + 1.300 + getStringProperty(device, "manufacturer", &(desc->Manufacturer)); 1.301 + getStringProperty(device, "product", &(desc->Product)); 1.302 + 1.303 + return true; 1.304 +} 1.305 + 1.306 +//----------------------------------------------------------------------------- 1.307 +bool HIDDeviceManager::GetDescriptorFromPath(const char* dev_path, HIDDeviceDesc* desc) 1.308 +{ 1.309 + if (!initializeManager()) 1.310 + { 1.311 + return false; 1.312 + } 1.313 + 1.314 + // Search for the udev device from the given pathname so we can 1.315 + // have a handle to query device properties 1.316 + 1.317 + udev_enumerate* devices = udev_enumerate_new(UdevInstance); 1.318 + udev_enumerate_add_match_subsystem(devices, "hidraw"); 1.319 + udev_enumerate_scan_devices(devices); 1.320 + 1.321 + udev_list_entry* entry = udev_enumerate_get_list_entry(devices); 1.322 + 1.323 + bool success = false; 1.324 + // Search for the device with the matching path 1.325 + while (entry != NULL) 1.326 + { 1.327 + // Get the device file name 1.328 + const char* sysfs_path = udev_list_entry_get_name(entry); 1.329 + udev_device* hid; // The device's HID udev node. 1.330 + hid = udev_device_new_from_syspath(UdevInstance, sysfs_path); 1.331 + const char* path = udev_device_get_devnode(hid); 1.332 + 1.333 + if (OVR_strcmp(dev_path, path) == 0) 1.334 + { // Found the device so lets collect the device descriptor 1.335 + 1.336 + // Get the USB device 1.337 + hid = udev_device_get_parent_with_subsystem_devtype(hid, "usb", "usb_device"); 1.338 + if (hid) 1.339 + { 1.340 + desc->Path = dev_path; 1.341 + success = getFullDesc(hid, desc); 1.342 + } 1.343 + 1.344 + } 1.345 + 1.346 + udev_device_unref(hid); 1.347 + entry = udev_list_entry_get_next(entry); 1.348 + } 1.349 + 1.350 + // Free the enumerator 1.351 + udev_enumerate_unref(devices); 1.352 + 1.353 + return success; 1.354 +} 1.355 + 1.356 +//----------------------------------------------------------------------------- 1.357 +void HIDDeviceManager::OnEvent(int i, int fd) 1.358 +{ 1.359 + // There is a device status change 1.360 + udev_device* hid = udev_monitor_receive_device(HIDMonitor); 1.361 + if (hid) 1.362 + { 1.363 + const char* dev_path = udev_device_get_devnode(hid); 1.364 + const char* action = udev_device_get_action(hid); 1.365 + 1.366 + HIDDeviceDesc device_info; 1.367 + device_info.Path = dev_path; 1.368 + 1.369 + MessageType notify_type; 1.370 + if (OVR_strcmp(action, "add") == 0) 1.371 + { 1.372 + notify_type = Message_DeviceAdded; 1.373 + 1.374 + // Retrieve the device info. This can only be done on a connected 1.375 + // device and is invalid for a disconnected device 1.376 + 1.377 + // Get the USB device 1.378 + hid = udev_device_get_parent_with_subsystem_devtype(hid, "usb", "usb_device"); 1.379 + if (!hid) 1.380 + { 1.381 + return; 1.382 + } 1.383 + 1.384 + getFullDesc(hid, &device_info); 1.385 + } 1.386 + else if (OVR_strcmp(action, "remove") == 0) 1.387 + { 1.388 + notify_type = Message_DeviceRemoved; 1.389 + } 1.390 + else 1.391 + { 1.392 + return; 1.393 + } 1.394 + 1.395 + bool error = false; 1.396 + bool deviceFound = false; 1.397 + for (UPInt i = 0; i < NotificationDevices.GetSize(); i++) 1.398 + { 1.399 + if (NotificationDevices[i] && 1.400 + NotificationDevices[i]->OnDeviceNotification(notify_type, &device_info, &error)) 1.401 + { 1.402 + // The notification was for an existing device 1.403 + deviceFound = true; 1.404 + break; 1.405 + } 1.406 + } 1.407 + 1.408 + if (notify_type == Message_DeviceAdded && !deviceFound) 1.409 + { 1.410 + DevManager->DetectHIDDevice(device_info); 1.411 + } 1.412 + 1.413 + udev_device_unref(hid); 1.414 + } 1.415 +} 1.416 + 1.417 +//============================================================================= 1.418 +// Linux::HIDDevice 1.419 +//============================================================================= 1.420 +HIDDevice::HIDDevice(HIDDeviceManager* manager) 1.421 + : HIDManager(manager), InMinimalMode(false) 1.422 +{ 1.423 + DeviceHandle = -1; 1.424 +} 1.425 + 1.426 +//----------------------------------------------------------------------------- 1.427 +// This is a minimal constructor used during enumeration for us to pass 1.428 +// a HIDDevice to the visit function (so that it can query feature reports). 1.429 +HIDDevice::HIDDevice(HIDDeviceManager* manager, int device_handle) 1.430 +: HIDManager(manager), DeviceHandle(device_handle), InMinimalMode(true) 1.431 +{ 1.432 +} 1.433 + 1.434 +//----------------------------------------------------------------------------- 1.435 +HIDDevice::~HIDDevice() 1.436 +{ 1.437 + if (!InMinimalMode) 1.438 + { 1.439 + HIDShutdown(); 1.440 + } 1.441 +} 1.442 + 1.443 +//----------------------------------------------------------------------------- 1.444 +bool HIDDevice::HIDInitialize(const String& path) 1.445 +{ 1.446 + const char* hid_path = path.ToCStr(); 1.447 + if (!openDevice(hid_path)) 1.448 + { 1.449 + LogText("OVR::Linux::HIDDevice - Failed to open HIDDevice: %s", hid_path); 1.450 + return false; 1.451 + } 1.452 + 1.453 + HIDManager->DevManager->pThread->AddTicksNotifier(this); 1.454 + HIDManager->AddNotificationDevice(this); 1.455 + 1.456 + LogText("OVR::Linux::HIDDevice - Opened '%s'\n" 1.457 + " Manufacturer:'%s' Product:'%s' Serial#:'%s'\n", 1.458 + DevDesc.Path.ToCStr(), 1.459 + DevDesc.Manufacturer.ToCStr(), DevDesc.Product.ToCStr(), 1.460 + DevDesc.SerialNumber.ToCStr()); 1.461 + 1.462 + return true; 1.463 +} 1.464 + 1.465 +//----------------------------------------------------------------------------- 1.466 +bool HIDDevice::initInfo() 1.467 +{ 1.468 + // Device must have been successfully opened. 1.469 + OVR_ASSERT(DeviceHandle >= 0); 1.470 + 1.471 + int desc_size = 0; 1.472 + hidraw_report_descriptor rpt_desc; 1.473 + memset(&rpt_desc, 0, sizeof(rpt_desc)); 1.474 + 1.475 + // get report descriptor size 1.476 + int r = ioctl(DeviceHandle, HIDIOCGRDESCSIZE, &desc_size); 1.477 + if (r < 0) 1.478 + { 1.479 + OVR_ASSERT_LOG(false, ("Failed to get report descriptor size.")); 1.480 + return false; 1.481 + } 1.482 + 1.483 + // Get the report descriptor 1.484 + rpt_desc.size = desc_size; 1.485 + r = ioctl(DeviceHandle, HIDIOCGRDESC, &rpt_desc); 1.486 + if (r < 0) 1.487 + { 1.488 + OVR_ASSERT_LOG(false, ("Failed to get report descriptor.")); 1.489 + return false; 1.490 + } 1.491 + 1.492 + /* 1.493 + // Get report lengths. 1.494 + SInt32 bufferLength; 1.495 + bool getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxInputReportSizeKey), &bufferLength); 1.496 + OVR_ASSERT(getResult); 1.497 + InputReportBufferLength = (UInt16) bufferLength; 1.498 + 1.499 + getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxOutputReportSizeKey), &bufferLength); 1.500 + OVR_ASSERT(getResult); 1.501 + OutputReportBufferLength = (UInt16) bufferLength; 1.502 + 1.503 + getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxFeatureReportSizeKey), &bufferLength); 1.504 + OVR_ASSERT(getResult); 1.505 + FeatureReportBufferLength = (UInt16) bufferLength; 1.506 + 1.507 + 1.508 + if (ReadBufferSize < InputReportBufferLength) 1.509 + { 1.510 + OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer.")); 1.511 + return false; 1.512 + } 1.513 + 1.514 + // Get device desc. 1.515 + if (!HIDManager->getFullDesc(Device, &DevDesc)) 1.516 + { 1.517 + OVR_ASSERT_LOG(false, ("Failed to get device desc while initializing device.")); 1.518 + return false; 1.519 + } 1.520 + 1.521 + return true; 1.522 + */ 1.523 + 1.524 + // Get report lengths. 1.525 +// TODO: hard-coded for now. Need to interpret these values from the report descriptor 1.526 + InputReportBufferLength = 62; 1.527 + OutputReportBufferLength = 0; 1.528 + FeatureReportBufferLength = 69; 1.529 + 1.530 + if (ReadBufferSize < InputReportBufferLength) 1.531 + { 1.532 + OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer.")); 1.533 + return false; 1.534 + } 1.535 + 1.536 + return true; 1.537 +} 1.538 + 1.539 +//----------------------------------------------------------------------------- 1.540 +bool HIDDevice::openDevice(const char* device_path) 1.541 +{ 1.542 + // First fill out the device descriptor 1.543 + if (!HIDManager->GetDescriptorFromPath(device_path, &DevDesc)) 1.544 + { 1.545 + return false; 1.546 + } 1.547 + 1.548 + // Now open the device 1.549 + DeviceHandle = open(device_path, O_RDWR); 1.550 + if (DeviceHandle < 0) 1.551 + { 1.552 + OVR_DEBUG_LOG(("Failed 'CreateHIDFile' while opening device, error = 0x%X.", errno)); 1.553 + DeviceHandle = -1; 1.554 + return false; 1.555 + } 1.556 + 1.557 + // fill out some values from the feature report descriptor 1.558 + if (!initInfo()) 1.559 + { 1.560 + OVR_ASSERT_LOG(false, ("Failed to get HIDDevice info.")); 1.561 + 1.562 + close(DeviceHandle); 1.563 + DeviceHandle = -1; 1.564 + return false; 1.565 + } 1.566 + 1.567 + // Add the device to the polling list 1.568 + if (!HIDManager->DevManager->pThread->AddSelectFd(this, DeviceHandle)) 1.569 + { 1.570 + OVR_ASSERT_LOG(false, ("Failed to initialize polling for HIDDevice.")); 1.571 + 1.572 + close(DeviceHandle); 1.573 + DeviceHandle = -1; 1.574 + return false; 1.575 + } 1.576 + 1.577 + return true; 1.578 +} 1.579 + 1.580 +//----------------------------------------------------------------------------- 1.581 +void HIDDevice::HIDShutdown() 1.582 +{ 1.583 + 1.584 + HIDManager->DevManager->pThread->RemoveTicksNotifier(this); 1.585 + HIDManager->RemoveNotificationDevice(this); 1.586 + 1.587 + if (DeviceHandle >= 0) // Device may already have been closed if unplugged. 1.588 + { 1.589 + closeDevice(false); 1.590 + } 1.591 + 1.592 + LogText("OVR::Linux::HIDDevice - HIDShutdown '%s'\n", DevDesc.Path.ToCStr()); 1.593 +} 1.594 + 1.595 +//----------------------------------------------------------------------------- 1.596 +void HIDDevice::closeDevice(bool wasUnplugged) 1.597 +{ 1.598 + OVR_ASSERT(DeviceHandle >= 0); 1.599 + 1.600 + 1.601 + HIDManager->DevManager->pThread->RemoveSelectFd(this, DeviceHandle); 1.602 + 1.603 + close(DeviceHandle); // close the file handle 1.604 + DeviceHandle = -1; 1.605 + 1.606 + LogText("OVR::Linux::HIDDevice - HID Device Closed '%s'\n", DevDesc.Path.ToCStr()); 1.607 +} 1.608 + 1.609 +//----------------------------------------------------------------------------- 1.610 +void HIDDevice::closeDeviceOnIOError() 1.611 +{ 1.612 + LogText("OVR::Linux::HIDDevice - Lost connection to '%s'\n", DevDesc.Path.ToCStr()); 1.613 + closeDevice(false); 1.614 +} 1.615 + 1.616 +//----------------------------------------------------------------------------- 1.617 +bool HIDDevice::SetFeatureReport(UByte* data, UInt32 length) 1.618 +{ 1.619 + 1.620 + if (DeviceHandle < 0) 1.621 + return false; 1.622 + 1.623 + UByte reportID = data[0]; 1.624 + 1.625 + if (reportID == 0) 1.626 + { 1.627 + // Not using reports so remove from data packet. 1.628 + data++; 1.629 + length--; 1.630 + } 1.631 + 1.632 + int r = ioctl(DeviceHandle, HIDIOCSFEATURE(length), data); 1.633 + return (r >= 0); 1.634 +} 1.635 + 1.636 +//----------------------------------------------------------------------------- 1.637 +bool HIDDevice::GetFeatureReport(UByte* data, UInt32 length) 1.638 +{ 1.639 + if (DeviceHandle < 0) 1.640 + return false; 1.641 + 1.642 + int r = ioctl(DeviceHandle, HIDIOCGFEATURE(length), data); 1.643 + return (r >= 0); 1.644 +} 1.645 + 1.646 +//----------------------------------------------------------------------------- 1.647 +UInt64 HIDDevice::OnTicks(UInt64 ticksMks) 1.648 +{ 1.649 + if (Handler) 1.650 + { 1.651 + return Handler->OnTicks(ticksMks); 1.652 + } 1.653 + 1.654 + return DeviceManagerThread::Notifier::OnTicks(ticksMks); 1.655 +} 1.656 + 1.657 +//----------------------------------------------------------------------------- 1.658 +void HIDDevice::OnEvent(int i, int fd) 1.659 +{ 1.660 + // We have data to read from the device 1.661 + int bytes = read(fd, ReadBuffer, ReadBufferSize); 1.662 + if (bytes >= 0) 1.663 + { 1.664 +// TODO: I need to handle partial messages and package reconstruction 1.665 + if (Handler) 1.666 + { 1.667 + Handler->OnInputReport(ReadBuffer, bytes); 1.668 + } 1.669 + } 1.670 + else 1.671 + { // Close the device on read error. 1.672 + closeDeviceOnIOError(); 1.673 + } 1.674 +} 1.675 + 1.676 +//----------------------------------------------------------------------------- 1.677 +bool HIDDevice::OnDeviceNotification(MessageType messageType, 1.678 + HIDDeviceDesc* device_info, 1.679 + bool* error) 1.680 +{ 1.681 + const char* device_path = device_info->Path.ToCStr(); 1.682 + 1.683 + if (messageType == Message_DeviceAdded && DeviceHandle < 0) 1.684 + { 1.685 + // Is this the correct device? 1.686 + if (!(device_info->VendorId == DevDesc.VendorId 1.687 + && device_info->ProductId == DevDesc.ProductId 1.688 + && device_info->SerialNumber == DevDesc.SerialNumber)) 1.689 + { 1.690 + return false; 1.691 + } 1.692 + 1.693 + // A closed device has been re-added. Try to reopen. 1.694 + if (!openDevice(device_path)) 1.695 + { 1.696 + LogError("OVR::Linux::HIDDevice - Failed to reopen a device '%s' that was re-added.\n", 1.697 + device_path); 1.698 + *error = true; 1.699 + return true; 1.700 + } 1.701 + 1.702 + LogText("OVR::Linux::HIDDevice - Reopened device '%s'\n", device_path); 1.703 + 1.704 + if (Handler) 1.705 + { 1.706 + Handler->OnDeviceMessage(HIDHandler::HIDDeviceMessage_DeviceAdded); 1.707 + } 1.708 + } 1.709 + else if (messageType == Message_DeviceRemoved) 1.710 + { 1.711 + // Is this the correct device? 1.712 + // For disconnected device, the device description will be invalid so 1.713 + // checking the path is the only way to match them 1.714 + if (DevDesc.Path.CompareNoCase(device_path) != 0) 1.715 + { 1.716 + return false; 1.717 + } 1.718 + 1.719 + if (DeviceHandle >= 0) 1.720 + { 1.721 + closeDevice(true); 1.722 + } 1.723 + 1.724 + if (Handler) 1.725 + { 1.726 + Handler->OnDeviceMessage(HIDHandler::HIDDeviceMessage_DeviceRemoved); 1.727 + } 1.728 + } 1.729 + else 1.730 + { 1.731 + OVR_ASSERT(0); 1.732 + } 1.733 + 1.734 + *error = false; 1.735 + return true; 1.736 +} 1.737 + 1.738 +//----------------------------------------------------------------------------- 1.739 +HIDDeviceManager* HIDDeviceManager::CreateInternal(Linux::DeviceManager* devManager) 1.740 +{ 1.741 + 1.742 + if (!System::IsInitialized()) 1.743 + { 1.744 + // Use custom message, since Log is not yet installed. 1.745 + OVR_DEBUG_STATEMENT(Log::GetDefaultLog()-> 1.746 + LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); ); 1.747 + return 0; 1.748 + } 1.749 + 1.750 + Ptr<Linux::HIDDeviceManager> manager = *new Linux::HIDDeviceManager(devManager); 1.751 + 1.752 + if (manager) 1.753 + { 1.754 + if (manager->Initialize()) 1.755 + { 1.756 + manager->AddRef(); 1.757 + } 1.758 + else 1.759 + { 1.760 + manager.Clear(); 1.761 + } 1.762 + } 1.763 + 1.764 + return manager.GetPtr(); 1.765 +} 1.766 + 1.767 +} // namespace Linux 1.768 + 1.769 +//------------------------------------------------------------------------------------- 1.770 +// ***** Creation 1.771 + 1.772 +// Creates a new HIDDeviceManager and initializes OVR. 1.773 +HIDDeviceManager* HIDDeviceManager::Create() 1.774 +{ 1.775 + OVR_ASSERT_LOG(false, ("Standalone mode not implemented yet.")); 1.776 + 1.777 + if (!System::IsInitialized()) 1.778 + { 1.779 + // Use custom message, since Log is not yet installed. 1.780 + OVR_DEBUG_STATEMENT(Log::GetDefaultLog()-> 1.781 + LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); ); 1.782 + return 0; 1.783 + } 1.784 + 1.785 + Ptr<Linux::HIDDeviceManager> manager = *new Linux::HIDDeviceManager(NULL); 1.786 + 1.787 + if (manager) 1.788 + { 1.789 + if (manager->Initialize()) 1.790 + { 1.791 + manager->AddRef(); 1.792 + } 1.793 + else 1.794 + { 1.795 + manager.Clear(); 1.796 + } 1.797 + } 1.798 + 1.799 + return manager.GetPtr(); 1.800 +} 1.801 + 1.802 +} // namespace OVR