Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 45 additions & 3 deletions HidSharp/Platform/Linux/LinuxHidDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ under the License. */
#endregion

using System;
using System.Globalization;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
Expand Down Expand Up @@ -90,6 +91,26 @@ internal static LinuxHidDevice TryCreate(string path)
return d;
}
}

// Devices without USB parents expose their identity through HID udev properties.
IntPtr hidParent = NativeMethodsLibudev.Instance.udev_device_get_parent_with_subsystem_devtype(device, "hid", null);
if (IntPtr.Zero != hidParent)
{
string hidId = NativeMethodsLibudev.Instance.udev_device_get_property_value(hidParent, "HID_ID");

int vid, pid;
if (TryParseHidId(hidId, out vid, out pid))
{
d._vid = vid;
d._pid = pid;
d._version = 0;
d._manufacturer = null;
d._productName = NativeMethodsLibudev.Instance.udev_device_get_property_value(hidParent, "HID_NAME");
d._serialNumber = null;

return d;
}
}
}
}
}
Expand All @@ -108,6 +129,23 @@ internal static LinuxHidDevice TryCreate(string path)
return null;
}

static bool TryParseHidId(string hidId, out int vid, out int pid)
{
vid = 0;
pid = 0;

if (hidId == null) { return false; }

// HID_ID is BUS:VID:PID.
string[] fields = hidId.Split(':');
if (fields.Length != 3) { return false; }

return int.TryParse(fields[1],
NumberStyles.HexNumber, CultureInfo.InvariantCulture, out vid) &&
int.TryParse(fields[2],
NumberStyles.HexNumber, CultureInfo.InvariantCulture, out pid);
}

protected override DeviceStream OpenDeviceDirectly(OpenConfiguration openConfig)
{
RequiresGetInfo();
Expand Down Expand Up @@ -282,10 +320,14 @@ unsafe string GetUsbPath()
{
using (var udev = new SafeUdevHandle(NativeMethodsLibudev.Instance.udev_new()))
{
var handle = NativeMethodsLibudev.Instance.udev_device_new_from_syspath(udev.DangerousGetHandle(), _path);
using (var parent = new SafeUdevDeviceHandle(NativeMethodsLibudev.Instance.udev_device_get_parent_with_subsystem_devtype(handle, "usb", "usb_device")))
var devicePtr = NativeMethodsLibudev.Instance.udev_device_new_from_syspath(udev.DangerousGetHandle(), _path);
using (var device = new SafeUdevDeviceHandle(devicePtr))
{
var parentPtr = parent.DangerousGetHandle();
if (device.IsInvalid) { throw DeviceException.CreateIOException(this, "Failed to find device in udev."); }

var parentPtr = NativeMethodsLibudev.Instance.udev_device_get_parent_with_subsystem_devtype(
device.DangerousGetHandle(), "usb", "usb_device");
if (parentPtr == IntPtr.Zero) { throw DeviceException.CreateIOException(this, "Device has no USB parent."); }

string devNum = NativeMethodsLibudev.Instance.udev_device_get_sysattr_value(parentPtr, "devnum");
string busNum = NativeMethodsLibudev.Instance.udev_device_get_sysattr_value(parentPtr, "busnum");
Expand Down
2 changes: 2 additions & 0 deletions HidSharp/Platform/Linux/NativeMethodsLibudev.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,7 @@ public abstract string FriendlyName
public abstract string udev_device_get_sysattr_value(IntPtr device, string sysattr);

public abstract int udev_device_get_is_initialized(IntPtr device);

public abstract string udev_device_get_property_value(IntPtr device, string key);
}
}
9 changes: 9 additions & 0 deletions HidSharp/Platform/Linux/NativeMethodsLibudev0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,5 +215,14 @@ public override int udev_device_get_is_initialized(IntPtr device)
{
return native_udev_device_get_is_initialized(device);
}

[DllImport(libudev, EntryPoint = "udev_device_get_property_value")]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
static extern string native_udev_device_get_property_value(IntPtr device,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string key);
public override string udev_device_get_property_value(IntPtr device, string key)
{
return native_udev_device_get_property_value(device, key);
}
}
}
9 changes: 9 additions & 0 deletions HidSharp/Platform/Linux/NativeMethodsLibudev1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,5 +215,14 @@ public override int udev_device_get_is_initialized(IntPtr device)
{
return native_udev_device_get_is_initialized(device);
}

[DllImport(libudev, EntryPoint = "udev_device_get_property_value")]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
static extern string native_udev_device_get_property_value(IntPtr device,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string key);
public override string udev_device_get_property_value(IntPtr device, string key)
{
return native_udev_device_get_property_value(device, key);
}
}
}