From b9e6f30ba835f5019db55d98631f6571fdc575ef Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Thu, 20 Feb 2020 16:11:42 +0100 Subject: kerneldevice,udev: don't assume interface is the direct parent object E.g. it may be one more layer up: looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8.4/1-8.4:1.1/ttyUSB1/tty/ttyUSB1': KERNEL=="ttyUSB1" SUBSYSTEM=="tty" DRIVER=="" looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8.4/1-8.4:1.1/ttyUSB1': KERNELS=="ttyUSB1" SUBSYSTEMS=="usb-serial" DRIVERS=="option1" ATTRS{port_number}=="0" looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8.4/1-8.4:1.1': KERNELS=="1-8.4:1.1" SUBSYSTEMS=="usb" DRIVERS=="option" ATTRS{bNumEndpoints}=="02" ATTRS{supports_autosuspend}=="1" ATTRS{bInterfaceNumber}=="01" ATTRS{bAlternateSetting}==" 0" ATTRS{bInterfaceSubClass}=="06" ATTRS{bInterfaceProtocol}=="13" ATTRS{interface}=="Huawei Mobile Connect - Application" ATTRS{bInterfaceClass}=="ff" ATTRS{authorized}=="1" --- src/kerneldevice/mm-kernel-device-udev.c | 62 +++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 16 deletions(-) (limited to 'src/kerneldevice/mm-kernel-device-udev.c') diff --git a/src/kerneldevice/mm-kernel-device-udev.c b/src/kerneldevice/mm-kernel-device-udev.c index 3dc3eeb7..620d1441 100644 --- a/src/kerneldevice/mm-kernel-device-udev.c +++ b/src/kerneldevice/mm-kernel-device-udev.c @@ -39,7 +39,7 @@ static GParamSpec *properties[PROP_LAST]; struct _MMKernelDeviceUdevPrivate { GUdevDevice *device; - GUdevDevice *parent; + GUdevDevice *interface; GUdevDevice *physdev; guint16 vendor; guint16 product; @@ -263,12 +263,42 @@ ensure_physdev (MMKernelDeviceUdev *self) /*****************************************************************************/ static void -ensure_parent (MMKernelDeviceUdev *self) +ensure_interface (MMKernelDeviceUdev *self) { - if (self->priv->parent) + GUdevDevice *new_parent; + GUdevDevice *parent; + + if (self->priv->interface) return; - if (self->priv->device) - self->priv->parent = g_udev_device_get_parent (self->priv->device); + + if (!self->priv->device) + return; + + ensure_physdev (self); + + parent = g_udev_device_get_parent (self->priv->device); + while (1) { + /* Abort if no parent found */ + if (!parent) + break; + + /* Look for the first parent that is a USB interface (i.e. has + * bInterfaceClass) */ + if (g_udev_device_has_sysfs_attr (parent, "bInterfaceClass")) { + self->priv->interface = parent; + break; + } + + /* If unknown physdev, just stop right away */ + if (!self->priv->physdev || parent == self->priv->physdev) { + g_object_unref (parent); + break; + } + + new_parent = g_udev_device_get_parent (parent); + g_object_unref (parent); + parent = new_parent; + } } /*****************************************************************************/ @@ -494,8 +524,8 @@ kernel_device_get_interface_class (MMKernelDevice *_self) g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), -1); self = MM_KERNEL_DEVICE_UDEV (_self); - ensure_parent (self); - return (self->priv->parent ? g_udev_device_get_sysfs_attr_as_int (self->priv->parent, "bInterfaceClass") : -1); + ensure_interface (self); + return (self->priv->interface ? g_udev_device_get_sysfs_attr_as_int (self->priv->interface, "bInterfaceClass") : -1); } static gint @@ -506,8 +536,8 @@ kernel_device_get_interface_subclass (MMKernelDevice *_self) g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), -1); self = MM_KERNEL_DEVICE_UDEV (_self); - ensure_parent (self); - return (self->priv->parent ? g_udev_device_get_sysfs_attr_as_int (self->priv->parent, "bInterfaceSubClass") : -1); + ensure_interface (self); + return (self->priv->interface ? g_udev_device_get_sysfs_attr_as_int (self->priv->interface, "bInterfaceSubClass") : -1); } static gint @@ -518,8 +548,8 @@ kernel_device_get_interface_protocol (MMKernelDevice *_self) g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), -1); self = MM_KERNEL_DEVICE_UDEV (_self); - ensure_parent (self); - return (self->priv->parent ? g_udev_device_get_sysfs_attr_as_int (self->priv->parent, "bInterfaceProtocol") : -1); + ensure_interface (self); + return (self->priv->interface ? g_udev_device_get_sysfs_attr_as_int (self->priv->interface, "bInterfaceProtocol") : -1); } static const gchar * @@ -530,8 +560,8 @@ kernel_device_get_interface_sysfs_path (MMKernelDevice *_self) g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), NULL); self = MM_KERNEL_DEVICE_UDEV (_self); - ensure_parent (self); - return (self->priv->parent ? g_udev_device_get_sysfs_path (self->priv->parent) : NULL); + ensure_interface (self); + return (self->priv->interface ? g_udev_device_get_sysfs_path (self->priv->interface) : NULL); } static const gchar * @@ -542,8 +572,8 @@ kernel_device_get_interface_description (MMKernelDevice *_self) g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), NULL); self = MM_KERNEL_DEVICE_UDEV (_self); - ensure_parent (self); - return (self->priv->parent ? g_udev_device_get_sysfs_attr (self->priv->parent, "interface") : NULL); + ensure_interface (self); + return (self->priv->interface ? g_udev_device_get_sysfs_attr (self->priv->interface, "interface") : NULL); } static gboolean @@ -906,7 +936,7 @@ dispose (GObject *object) MMKernelDeviceUdev *self = MM_KERNEL_DEVICE_UDEV (object); g_clear_object (&self->priv->physdev); - g_clear_object (&self->priv->parent); + g_clear_object (&self->priv->interface); g_clear_object (&self->priv->device); g_clear_object (&self->priv->properties); -- cgit v1.2.3-70-g09d2