mirror of
https://github.com/mii443/rust-openvr.git
synced 2025-08-25 17:49:24 +00:00
820 lines
24 KiB
C++
820 lines
24 KiB
C++
/************************************************************************************
|
|
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
|