summaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/OVR_Linux_HIDDevice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'LibOVR/Src/OVR_Linux_HIDDevice.cpp')
-rw-r--r--LibOVR/Src/OVR_Linux_HIDDevice.cpp819
1 files changed, 0 insertions, 819 deletions
diff --git a/LibOVR/Src/OVR_Linux_HIDDevice.cpp b/LibOVR/Src/OVR_Linux_HIDDevice.cpp
deleted file mode 100644
index 133e5c3..0000000
--- a/LibOVR/Src/OVR_Linux_HIDDevice.cpp
+++ /dev/null
@@ -1,819 +0,0 @@
-/************************************************************************************
-Filename : OVR_Linux_HIDDevice.cpp
-Content : Linux HID device implementation.
-Created : February 26, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
-
-Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
-you may not use the Oculus VR Rift SDK except in compliance with the License,
-which is provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-You may obtain a copy of the License at
-
-http://www.oculusvr.com/licenses/LICENSE-3.1
-
-Unless required by applicable law or agreed to in writing, the Oculus VR SDK
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-*************************************************************************************/
-
-#include "OVR_Linux_HIDDevice.h"
-
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <linux/hidraw.h>
-#include "OVR_HIDDeviceImpl.h"
-
-namespace OVR { namespace Linux {
-
-static const UInt32 MAX_QUEUED_INPUT_REPORTS = 5;
-
-//-------------------------------------------------------------------------------------
-// **** Linux::DeviceManager
-//-----------------------------------------------------------------------------
-HIDDeviceManager::HIDDeviceManager(DeviceManager* manager) : DevManager(manager)
-{
- UdevInstance = NULL;
- HIDMonitor = NULL;
- HIDMonHandle = -1;
-}
-
-//-----------------------------------------------------------------------------
-HIDDeviceManager::~HIDDeviceManager()
-{
-}
-
-//-----------------------------------------------------------------------------
-bool HIDDeviceManager::initializeManager()
-{
- if (HIDMonitor)
- {
- return true;
- }
-
- // Create a udev_monitor handle to watch for device changes (hot-plug detection)
- HIDMonitor = udev_monitor_new_from_netlink(UdevInstance, "udev");
- if (HIDMonitor == NULL)
- {
- return false;
- }
-
- udev_monitor_filter_add_match_subsystem_devtype(HIDMonitor, "hidraw", NULL); // filter for hidraw only
-
- int err = udev_monitor_enable_receiving(HIDMonitor);
- if (err)
- {
- udev_monitor_unref(HIDMonitor);
- HIDMonitor = NULL;
- return false;
- }
-
- // Get the file descriptor (fd) for the monitor.
- HIDMonHandle = udev_monitor_get_fd(HIDMonitor);
- if (HIDMonHandle < 0)
- {
- udev_monitor_unref(HIDMonitor);
- HIDMonitor = NULL;
- return false;
- }
-
- // This file handle will be polled along-side with the device hid handles for changes
- // Add the handle to the polling list
- if (!DevManager->pThread->AddSelectFd(this, HIDMonHandle))
- {
- close(HIDMonHandle);
- HIDMonHandle = -1;
-
- udev_monitor_unref(HIDMonitor);
- HIDMonitor = NULL;
- return false;
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-bool HIDDeviceManager::Initialize()
-{
- // Get a udev library handle. This handle must stay active during the
- // duration the lifetime of device monitoring handles
- UdevInstance = udev_new();
- if (!UdevInstance)
- return false;
-
- return initializeManager();
-}
-
-//-----------------------------------------------------------------------------
-void HIDDeviceManager::Shutdown()
-{
- OVR_ASSERT_LOG((UdevInstance), ("Should have called 'Initialize' before 'Shutdown'."));
-
- if (HIDMonitor)
- {
- DevManager->pThread->RemoveSelectFd(this, HIDMonHandle);
- close(HIDMonHandle);
- HIDMonHandle = -1;
-
- udev_monitor_unref(HIDMonitor);
- HIDMonitor = NULL;
- }
-
- udev_unref(UdevInstance); // release the library
-
- LogText("OVR::Linux::HIDDeviceManager - shutting down.\n");
-}
-
-//-------------------------------------------------------------------------------
-bool HIDDeviceManager::AddNotificationDevice(HIDDevice* device)
-{
- NotificationDevices.PushBack(device);
- return true;
-}
-
-//-------------------------------------------------------------------------------
-bool HIDDeviceManager::RemoveNotificationDevice(HIDDevice* device)
-{
- for (UPInt i = 0; i < NotificationDevices.GetSize(); i++)
- {
- if (NotificationDevices[i] == device)
- {
- NotificationDevices.RemoveAt(i);
- return true;
- }
- }
- return false;
-}
-
-//-----------------------------------------------------------------------------
-bool HIDDeviceManager::getIntProperty(udev_device* device,
- const char* propertyName,
- SInt32* pResult)
-{
- const char* str = udev_device_get_sysattr_value(device, propertyName);
- if (str)
- {
- *pResult = strtol(str, NULL, 16);
- return true;
- }
- else
- {
- *pResult = 0;
- return true;
- }
-}
-
-//-----------------------------------------------------------------------------
-bool HIDDeviceManager::initVendorProductVersion(udev_device* device, HIDDeviceDesc* pDevDesc)
-{
- SInt32 result;
- if (getIntProperty(device, "idVendor", &result))
- pDevDesc->VendorId = result;
- else
- return false;
-
- if (getIntProperty(device, "idProduct", &result))
- pDevDesc->ProductId = result;
- else
- return false;
-
- if (getIntProperty(device, "bcdDevice", &result))
- pDevDesc->VersionNumber = result;
- else
- return false;
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-bool HIDDeviceManager::getStringProperty(udev_device* device,
- const char* propertyName,
- OVR::String* pResult)
-{
- // Get the attribute in UTF8
- const char* str = udev_device_get_sysattr_value(device, propertyName);
- if (str)
- { // Copy the string into the return value
- *pResult = String(str);
- return true;
- }
- else
- {
- return false;
- }
-}
-
-//-----------------------------------------------------------------------------
-bool HIDDeviceManager::Enumerate(HIDEnumerateVisitor* enumVisitor)
-{
-
- if (!initializeManager())
- {
- return false;
- }
-
- // Get a list of hid devices
- udev_enumerate* devices = udev_enumerate_new(UdevInstance);
- udev_enumerate_add_match_subsystem(devices, "hidraw");
- udev_enumerate_scan_devices(devices);
-
- udev_list_entry* entry = udev_enumerate_get_list_entry(devices);
-
- // Search each device for the matching vid/pid
- while (entry != NULL)
- {
- // Get the device file name
- const char* sysfs_path = udev_list_entry_get_name(entry);
- udev_device* hid; // The device's HID udev node.
- hid = udev_device_new_from_syspath(UdevInstance, sysfs_path);
- const char* dev_path = udev_device_get_devnode(hid);
-
- // Get the USB device
- hid = udev_device_get_parent_with_subsystem_devtype(hid, "usb", "usb_device");
- if (hid)
- {
- HIDDeviceDesc devDesc;
-
- // Check the VID/PID for a match
- if (dev_path &&
- initVendorProductVersion(hid, &devDesc) &&
- enumVisitor->MatchVendorProduct(devDesc.VendorId, devDesc.ProductId))
- {
- devDesc.Path = dev_path;
- getFullDesc(hid, &devDesc);
-
- // Look for the device to check if it is already opened.
- Ptr<DeviceCreateDesc> existingDevice = DevManager->FindHIDDevice(devDesc, true);
- // if device exists and it is opened then most likely the device open()
- // will fail; therefore, we just set Enumerated to 'true' and continue.
- if (existingDevice && existingDevice->pDevice)
- {
- existingDevice->Enumerated = true;
- }
- else
- { // open the device temporarily for startup communication
- int device_handle = open(dev_path, O_RDWR);
- if (device_handle >= 0)
- {
- // Construct minimal device that the visitor callback can get feature reports from
- Linux::HIDDevice device(this, device_handle);
- enumVisitor->Visit(device, devDesc);
-
- close(device_handle); // close the file handle
- }
- }
- }
-
- udev_device_unref(hid);
- entry = udev_list_entry_get_next(entry);
- }
- }
-
- // Free the enumerator and udev objects
- udev_enumerate_unref(devices);
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-OVR::HIDDevice* HIDDeviceManager::Open(const String& path)
-{
- Ptr<Linux::HIDDevice> device = *new Linux::HIDDevice(this);
-
- if (device->HIDInitialize(path))
- {
- device->AddRef();
- return device;
- }
-
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-bool HIDDeviceManager::getFullDesc(udev_device* device, HIDDeviceDesc* desc)
-{
-
- if (!initVendorProductVersion(device, desc))
- {
- return false;
- }
-
- if (!getStringProperty(device, "serial", &(desc->SerialNumber)))
- {
- return false;
- }
-
- getStringProperty(device, "manufacturer", &(desc->Manufacturer));
- getStringProperty(device, "product", &(desc->Product));
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-bool HIDDeviceManager::GetDescriptorFromPath(const char* dev_path, HIDDeviceDesc* desc)
-{
- if (!initializeManager())
- {
- return false;
- }
-
- // Search for the udev device from the given pathname so we can
- // have a handle to query device properties
-
- udev_enumerate* devices = udev_enumerate_new(UdevInstance);
- udev_enumerate_add_match_subsystem(devices, "hidraw");
- udev_enumerate_scan_devices(devices);
-
- udev_list_entry* entry = udev_enumerate_get_list_entry(devices);
-
- bool success = false;
- // Search for the device with the matching path
- while (entry != NULL)
- {
- // Get the device file name
- const char* sysfs_path = udev_list_entry_get_name(entry);
- udev_device* hid; // The device's HID udev node.
- hid = udev_device_new_from_syspath(UdevInstance, sysfs_path);
- const char* path = udev_device_get_devnode(hid);
-
- if (OVR_strcmp(dev_path, path) == 0)
- { // Found the device so lets collect the device descriptor
-
- // Get the USB device
- hid = udev_device_get_parent_with_subsystem_devtype(hid, "usb", "usb_device");
- if (hid)
- {
- desc->Path = dev_path;
- success = getFullDesc(hid, desc);
- }
-
- }
-
- udev_device_unref(hid);
- entry = udev_list_entry_get_next(entry);
- }
-
- // Free the enumerator
- udev_enumerate_unref(devices);
-
- return success;
-}
-
-//-----------------------------------------------------------------------------
-void HIDDeviceManager::OnEvent(int i, int fd)
-{
- OVR_UNUSED(i);
- OVR_UNUSED(fd);
-
- // There is a device status change
- udev_device* hid = udev_monitor_receive_device(HIDMonitor);
- if (hid)
- {
- const char* dev_path = udev_device_get_devnode(hid);
- const char* action = udev_device_get_action(hid);
-
- HIDDeviceDesc device_info;
- device_info.Path = dev_path;
-
- MessageType notify_type;
- if (OVR_strcmp(action, "add") == 0)
- {
- notify_type = Message_DeviceAdded;
-
- // Retrieve the device info. This can only be done on a connected
- // device and is invalid for a disconnected device
-
- // Get the USB device
- hid = udev_device_get_parent_with_subsystem_devtype(hid, "usb", "usb_device");
- if (!hid)
- {
- return;
- }
-
- getFullDesc(hid, &device_info);
- }
- else if (OVR_strcmp(action, "remove") == 0)
- {
- notify_type = Message_DeviceRemoved;
- }
- else
- {
- return;
- }
-
- bool error = false;
- bool deviceFound = false;
- for (UPInt i = 0; i < NotificationDevices.GetSize(); i++)
- {
- if (NotificationDevices[i] &&
- NotificationDevices[i]->OnDeviceNotification(notify_type, &device_info, &error))
- {
- // The notification was for an existing device
- deviceFound = true;
- break;
- }
- }
-
- if (notify_type == Message_DeviceAdded && !deviceFound)
- {
- DevManager->DetectHIDDevice(device_info);
- }
-
- udev_device_unref(hid);
- }
-}
-
-//=============================================================================
-// Linux::HIDDevice
-//=============================================================================
-HIDDevice::HIDDevice(HIDDeviceManager* manager)
- : InMinimalMode(false), HIDManager(manager)
-{
- DeviceHandle = -1;
-}
-
-//-----------------------------------------------------------------------------
-// This is a minimal constructor used during enumeration for us to pass
-// a HIDDevice to the visit function (so that it can query feature reports).
-HIDDevice::HIDDevice(HIDDeviceManager* manager, int device_handle)
-: InMinimalMode(true), HIDManager(manager), DeviceHandle(device_handle)
-{
-}
-
-//-----------------------------------------------------------------------------
-HIDDevice::~HIDDevice()
-{
- if (!InMinimalMode)
- {
- HIDShutdown();
- }
-}
-
-//-----------------------------------------------------------------------------
-bool HIDDevice::HIDInitialize(const String& path)
-{
- const char* hid_path = path.ToCStr();
- if (!openDevice(hid_path))
- {
- LogText("OVR::Linux::HIDDevice - Failed to open HIDDevice: %s", hid_path);
- return false;
- }
-
- HIDManager->DevManager->pThread->AddTicksNotifier(this);
- HIDManager->AddNotificationDevice(this);
-
- LogText("OVR::Linux::HIDDevice - Opened '%s'\n"
- " Manufacturer:'%s' Product:'%s' Serial#:'%s'\n",
- DevDesc.Path.ToCStr(),
- DevDesc.Manufacturer.ToCStr(), DevDesc.Product.ToCStr(),
- DevDesc.SerialNumber.ToCStr());
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-bool HIDDevice::initInfo()
-{
- // Device must have been successfully opened.
- OVR_ASSERT(DeviceHandle >= 0);
-
- int desc_size = 0;
- hidraw_report_descriptor rpt_desc;
- memset(&rpt_desc, 0, sizeof(rpt_desc));
-
- // get report descriptor size
- int r = ioctl(DeviceHandle, HIDIOCGRDESCSIZE, &desc_size);
- if (r < 0)
- {
- OVR_ASSERT_LOG(false, ("Failed to get report descriptor size."));
- return false;
- }
-
- // Get the report descriptor
- rpt_desc.size = desc_size;
- r = ioctl(DeviceHandle, HIDIOCGRDESC, &rpt_desc);
- if (r < 0)
- {
- OVR_ASSERT_LOG(false, ("Failed to get report descriptor."));
- return false;
- }
-
- /*
- // Get report lengths.
- SInt32 bufferLength;
- bool getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxInputReportSizeKey), &bufferLength);
- OVR_ASSERT(getResult);
- InputReportBufferLength = (UInt16) bufferLength;
-
- getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxOutputReportSizeKey), &bufferLength);
- OVR_ASSERT(getResult);
- OutputReportBufferLength = (UInt16) bufferLength;
-
- getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxFeatureReportSizeKey), &bufferLength);
- OVR_ASSERT(getResult);
- FeatureReportBufferLength = (UInt16) bufferLength;
-
-
- if (ReadBufferSize < InputReportBufferLength)
- {
- OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer."));
- return false;
- }
-
- // Get device desc.
- if (!HIDManager->getFullDesc(Device, &DevDesc))
- {
- OVR_ASSERT_LOG(false, ("Failed to get device desc while initializing device."));
- return false;
- }
-
- return true;
- */
-
- // Get report lengths.
-// TODO: hard-coded for now. Need to interpret these values from the report descriptor
- InputReportBufferLength = 62;
- OutputReportBufferLength = 0;
- FeatureReportBufferLength = 69;
-
- if (ReadBufferSize < InputReportBufferLength)
- {
- OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer."));
- return false;
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-bool HIDDevice::openDevice(const char* device_path)
-{
- // First fill out the device descriptor
- if (!HIDManager->GetDescriptorFromPath(device_path, &DevDesc))
- {
- return false;
- }
-
- // Now open the device
- DeviceHandle = open(device_path, O_RDWR);
- if (DeviceHandle < 0)
- {
- OVR_DEBUG_LOG(("Failed 'CreateHIDFile' while opening device, error = 0x%X.", errno));
- DeviceHandle = -1;
- return false;
- }
-
- // fill out some values from the feature report descriptor
- if (!initInfo())
- {
- OVR_ASSERT_LOG(false, ("Failed to get HIDDevice info."));
-
- close(DeviceHandle);
- DeviceHandle = -1;
- return false;
- }
-
- // Add the device to the polling list
- if (!HIDManager->DevManager->pThread->AddSelectFd(this, DeviceHandle))
- {
- OVR_ASSERT_LOG(false, ("Failed to initialize polling for HIDDevice."));
-
- close(DeviceHandle);
- DeviceHandle = -1;
- return false;
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-void HIDDevice::HIDShutdown()
-{
-
- HIDManager->DevManager->pThread->RemoveTicksNotifier(this);
- HIDManager->RemoveNotificationDevice(this);
-
- if (DeviceHandle >= 0) // Device may already have been closed if unplugged.
- {
- closeDevice(false);
- }
-
- LogText("OVR::Linux::HIDDevice - HIDShutdown '%s'\n", DevDesc.Path.ToCStr());
-}
-
-//-----------------------------------------------------------------------------
-void HIDDevice::closeDevice(bool wasUnplugged)
-{
- OVR_UNUSED(wasUnplugged);
- OVR_ASSERT(DeviceHandle >= 0);
-
-
- HIDManager->DevManager->pThread->RemoveSelectFd(this, DeviceHandle);
-
- close(DeviceHandle); // close the file handle
- DeviceHandle = -1;
-
- LogText("OVR::Linux::HIDDevice - HID Device Closed '%s'\n", DevDesc.Path.ToCStr());
-}
-
-//-----------------------------------------------------------------------------
-void HIDDevice::closeDeviceOnIOError()
-{
- LogText("OVR::Linux::HIDDevice - Lost connection to '%s'\n", DevDesc.Path.ToCStr());
- closeDevice(false);
-}
-
-//-----------------------------------------------------------------------------
-bool HIDDevice::SetFeatureReport(UByte* data, UInt32 length)
-{
-
- if (DeviceHandle < 0)
- return false;
-
- UByte reportID = data[0];
-
- if (reportID == 0)
- {
- // Not using reports so remove from data packet.
- data++;
- length--;
- }
-
- int r = ioctl(DeviceHandle, HIDIOCSFEATURE(length), data);
- return (r >= 0);
-}
-
-//-----------------------------------------------------------------------------
-bool HIDDevice::GetFeatureReport(UByte* data, UInt32 length)
-{
- if (DeviceHandle < 0)
- return false;
-
- int r = ioctl(DeviceHandle, HIDIOCGFEATURE(length), data);
- return (r >= 0);
-}
-
-//-----------------------------------------------------------------------------
-double HIDDevice::OnTicks(double tickSeconds)
-{
- if (Handler)
- {
- return Handler->OnTicks(tickSeconds);
- }
-
- return DeviceManagerThread::Notifier::OnTicks(tickSeconds);
-}
-
-//-----------------------------------------------------------------------------
-void HIDDevice::OnEvent(int i, int fd)
-{
- OVR_UNUSED(i);
- // We have data to read from the device
- int bytes = read(fd, ReadBuffer, ReadBufferSize);
- if (bytes >= 0)
- {
-// TODO: I need to handle partial messages and package reconstruction
- if (Handler)
- {
- Handler->OnInputReport(ReadBuffer, bytes);
- }
- }
- else
- { // Close the device on read error.
- closeDeviceOnIOError();
- }
-}
-
-//-----------------------------------------------------------------------------
-bool HIDDevice::OnDeviceNotification(MessageType messageType,
- HIDDeviceDesc* device_info,
- bool* error)
-{
- const char* device_path = device_info->Path.ToCStr();
-
- if (messageType == Message_DeviceAdded && DeviceHandle < 0)
- {
- // Is this the correct device?
- if (!(device_info->VendorId == DevDesc.VendorId
- && device_info->ProductId == DevDesc.ProductId
- && device_info->SerialNumber == DevDesc.SerialNumber))
- {
- return false;
- }
-
- // A closed device has been re-added. Try to reopen.
- if (!openDevice(device_path))
- {
- LogError("OVR::Linux::HIDDevice - Failed to reopen a device '%s' that was re-added.\n",
- device_path);
- *error = true;
- return true;
- }
-
- LogText("OVR::Linux::HIDDevice - Reopened device '%s'\n", device_path);
-
- if (Handler)
- {
- Handler->OnDeviceMessage(HIDHandler::HIDDeviceMessage_DeviceAdded);
- }
- }
- else if (messageType == Message_DeviceRemoved)
- {
- // Is this the correct device?
- // For disconnected device, the device description will be invalid so
- // checking the path is the only way to match them
- if (DevDesc.Path.CompareNoCase(device_path) != 0)
- {
- return false;
- }
-
- if (DeviceHandle >= 0)
- {
- closeDevice(true);
- }
-
- if (Handler)
- {
- Handler->OnDeviceMessage(HIDHandler::HIDDeviceMessage_DeviceRemoved);
- }
- }
- else
- {
- OVR_ASSERT(0);
- }
-
- *error = false;
- return true;
-}
-
-//-----------------------------------------------------------------------------
-HIDDeviceManager* HIDDeviceManager::CreateInternal(Linux::DeviceManager* devManager)
-{
-
- if (!System::IsInitialized())
- {
- // Use custom message, since Log is not yet installed.
- OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
- LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
- return 0;
- }
-
- Ptr<Linux::HIDDeviceManager> manager = *new Linux::HIDDeviceManager(devManager);
-
- if (manager)
- {
- if (manager->Initialize())
- {
- manager->AddRef();
- }
- else
- {
- manager.Clear();
- }
- }
-
- return manager.GetPtr();
-}
-
-} // namespace Linux
-
-//-------------------------------------------------------------------------------------
-// ***** Creation
-
-// Creates a new HIDDeviceManager and initializes OVR.
-HIDDeviceManager* HIDDeviceManager::Create(Ptr<OVR::DeviceManager>& deviceManager)
-{
-
- if (!System::IsInitialized())
- {
- // Use custom message, since Log is not yet installed.
- OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
- LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
- return 0;
- }
-
- Ptr<Linux::DeviceManager> deviceManagerLinux = *new Linux::DeviceManager;
-
- if (!deviceManagerLinux)
- {
- return NULL;
- }
-
- if (!deviceManagerLinux->Initialize(NULL))
- {
- return NULL;
- }
-
- deviceManager = deviceManagerLinux;
-
- return deviceManagerLinux->GetHIDDeviceManager();
-}
-
-} // namespace OVR