blob: 7fede02205fbfd1a83e2d667fa7d3445b237d947 [file]
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details:
*
* Copyright (C) 2016 Velocloud, Inc.
* Copyright (C) 2020 Aleksander Morgado <aleksander@aleksander.es>
*/
#include <string.h>
#define _LIBMM_INSIDE_MM
#include <libmm-glib.h>
#include <ModemManager-tags.h>
#include "mm-kernel-device-udev.h"
#include "mm-kernel-device-helpers.h"
#include "mm-log-object.h"
static void initable_iface_init (GInitableIface *iface);
G_DEFINE_TYPE_EXTENDED (MMKernelDeviceUdev, mm_kernel_device_udev, MM_TYPE_KERNEL_DEVICE, 0,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init))
enum {
PROP_0,
PROP_UDEV_CLIENT,
PROP_UDEV_DEVICE,
PROP_PROPERTIES,
PROP_LAST
};
static GParamSpec *properties[PROP_LAST];
struct _MMKernelDeviceUdevPrivate {
GUdevClient *client;
GUdevDevice *device;
GUdevDevice *interface;
GUdevDevice *physdev;
guint16 vendor;
guint16 product;
guint16 subsystem_vendor;
guint16 subsystem_device;
guint16 revision;
gchar *driver;
MMKernelEventProperties *properties;
};
/*****************************************************************************/
static guint
udev_device_get_sysfs_attr_as_hex (GUdevDevice *device,
const gchar *attribute)
{
const gchar *attr;
guint val = 0;
attr = g_udev_device_get_sysfs_attr (device, attribute);
if (attr)
mm_get_uint_from_hex_str (attr, &val);
return val;
}
/*****************************************************************************/
static void
preload_contents_other (MMKernelDeviceUdev *self)
{
g_autofree gchar *lower_device_name = NULL;
/* For any other kind of bus (or the absence of one, as in virtual devices),
* assume this is a single port device and don't try to match multiple ports
* together. Also, obviously, no vendor, product, revision or interface. */
self->priv->driver = g_strdup (g_udev_device_get_driver (self->priv->device));
/* But look for a lower real physical device, as we may have one */
lower_device_name = mm_kernel_device_get_lower_device_name (g_udev_device_get_sysfs_path (self->priv->device));
if (lower_device_name) {
g_autoptr(GUdevDevice) lower_device = NULL;
const gchar *subsystem;
subsystem = g_udev_device_get_subsystem (self->priv->device);
lower_device = g_udev_client_query_by_subsystem_and_name (self->priv->client, subsystem, lower_device_name);
if (!lower_device) {
mm_obj_dbg (self, "couldn't find lower device: %s/%s", subsystem, lower_device_name);
} else {
g_autoptr(MMKernelDevice) lower_kernel_device = NULL;
mm_obj_dbg (self, "setting up lower device: %s/%s", subsystem, lower_device_name);
lower_kernel_device = mm_kernel_device_udev_new (self->priv->client, lower_device);
g_object_set (self,
"lower-device", lower_kernel_device,
NULL);
}
}
}
static void
preload_contents_platform (MMKernelDeviceUdev *self,
const gchar *platform)
{
g_autoptr(GUdevDevice) iter = NULL;
iter = g_object_ref (self->priv->device);
while (iter) {
GUdevDevice *parent;
/* Store the first driver found */
if (!self->priv->driver)
self->priv->driver = g_strdup (g_udev_device_get_driver (iter));
/* Take first parent with the given platform subsystem as physical device */
if (!self->priv->physdev && (g_strcmp0 (g_udev_device_get_subsystem (iter), platform) == 0)) {
self->priv->physdev = g_object_ref (iter);
/* stop traversing as soon as the physical device is found */
break;
}
parent = g_udev_device_get_parent (iter);
g_clear_object (&iter);
iter = parent;
}
}
static void
preload_contents_pcmcia (MMKernelDeviceUdev *self)
{
g_autoptr(GUdevDevice) iter = NULL;
gboolean pcmcia_subsystem_found = FALSE;
iter = g_object_ref (self->priv->device);
while (iter) {
g_autoptr(GUdevDevice) parent = NULL;
/* Store the first driver found */
if (!self->priv->driver)
self->priv->driver = g_strdup (g_udev_device_get_driver (iter));
if (g_strcmp0 (g_udev_device_get_subsystem (iter), "pcmcia") == 0)
pcmcia_subsystem_found = TRUE;
/* If the parent of this PCMCIA device is no longer part of
* the PCMCIA subsystem, we want to stop since we're looking
* for the base PCMCIA device, not the PCMCIA controller which
* is usually PCI or some other bus type.
*/
parent = g_udev_device_get_parent (iter);
if (pcmcia_subsystem_found && parent && (g_strcmp0 (g_udev_device_get_subsystem (parent), "pcmcia") != 0)) {
self->priv->vendor = udev_device_get_sysfs_attr_as_hex (iter, "manf_id");
self->priv->product = udev_device_get_sysfs_attr_as_hex (iter, "card_id");
self->priv->physdev = g_object_ref (iter);
/* stop traversing as soon as the physical device is found */
break;
}
g_clear_object (&iter);
iter = g_steal_pointer (&parent);
}
}
static void
preload_contents_pci (MMKernelDeviceUdev *self)
{
g_autoptr(GUdevDevice) iter = NULL;
iter = g_object_ref (self->priv->device);
while (iter) {
GUdevDevice *parent;
/* Store the first driver found */
if (!self->priv->driver)
self->priv->driver = g_strdup (g_udev_device_get_driver (iter));
/* the PCI channel specific devices have their own drivers and
* subsystems, we can rely on the physical device being the first
* one that reports the 'pci' subsystem */
if (!self->priv->physdev && (g_strcmp0 (g_udev_device_get_subsystem (iter), "pci") == 0)) {
self->priv->vendor = udev_device_get_sysfs_attr_as_hex (iter, "vendor");
self->priv->product = udev_device_get_sysfs_attr_as_hex (iter, "device");
self->priv->subsystem_vendor = udev_device_get_sysfs_attr_as_hex (iter, "subsystem_vendor");
self->priv->subsystem_device = udev_device_get_sysfs_attr_as_hex (iter, "subsystem_device");
self->priv->revision = udev_device_get_sysfs_attr_as_hex (iter, "revision");
self->priv->physdev = g_object_ref (iter);
/* stop traversing as soon as the physical device is found */
break;
}
parent = g_udev_device_get_parent (iter);
g_clear_object (&iter);
iter = parent;
}
}
static void
preload_contents_usb (MMKernelDeviceUdev *self)
{
g_autoptr(GUdevDevice) iter = NULL;
iter = g_object_ref (self->priv->device);
while (iter) {
GUdevDevice *parent;
const gchar *devtype;
devtype = g_udev_device_get_devtype (iter);
/* is this the USB interface? */
if (!self->priv->interface && (g_strcmp0 (devtype, "usb_interface") == 0)) {
self->priv->interface = g_object_ref (iter);
self->priv->driver = g_strdup (g_udev_device_get_driver (iter));
}
/* is this the USB physdev? */
if (!self->priv->physdev && (g_strcmp0 (devtype, "usb_device") == 0)) {
self->priv->vendor = udev_device_get_sysfs_attr_as_hex (iter, "idVendor");
self->priv->product = udev_device_get_sysfs_attr_as_hex (iter, "idProduct");
self->priv->revision = udev_device_get_sysfs_attr_as_hex (iter, "bcdDevice");
self->priv->physdev = g_object_ref (iter);
/* stop traversing as soon as the physical device is found */
break;
}
parent = g_udev_device_get_parent (iter);
g_clear_object (&iter);
iter = parent;
}
}
static gchar *
find_device_bus_subsystem (MMKernelDeviceUdev *self)
{
g_autoptr(GUdevDevice) iter = NULL;
iter = g_object_ref (self->priv->device);
while (iter) {
const gchar *subsys;
GUdevDevice *parent;
/* stop search as soon as we find a parent object
* of one of the supported bus subsystems */
subsys = g_udev_device_get_subsystem (iter);
if ((g_strcmp0 (subsys, "usb") == 0) ||
(g_strcmp0 (subsys, "pcmcia") == 0) ||
(g_strcmp0 (subsys, "pci") == 0) ||
(g_strcmp0 (subsys, "platform") == 0) ||
(g_strcmp0 (subsys, "pnp") == 0) ||
(g_strcmp0 (subsys, "sdio") == 0))
return g_strdup (subsys);
parent = g_udev_device_get_parent (iter);
g_clear_object (&iter);
iter = parent;
}
/* no more parents to check */
return NULL;
}
static void
preload_contents (MMKernelDeviceUdev *self)
{
g_autofree gchar *bus_subsys = NULL;
bus_subsys = find_device_bus_subsystem (self);
if (g_strcmp0 (bus_subsys, "usb") == 0)
preload_contents_usb (self);
else if (g_strcmp0 (bus_subsys, "pcmcia") == 0)
preload_contents_pcmcia (self);
else if (g_strcmp0 (bus_subsys, "pci") == 0)
preload_contents_pci (self);
else if ((g_strcmp0 (bus_subsys, "platform") == 0) ||
(g_strcmp0 (bus_subsys, "pnp") == 0) ||
(g_strcmp0 (bus_subsys, "sdio") == 0))
preload_contents_platform (self, bus_subsys);
else
preload_contents_other (self);
if (!bus_subsys)
return;
mm_obj_dbg (self, "port contents loaded:");
mm_obj_dbg (self, " bus: %s", bus_subsys ? bus_subsys : "n/a");
if (self->priv->interface)
mm_obj_dbg (self, " interface: %s", g_udev_device_get_sysfs_path (self->priv->interface));
if (self->priv->physdev)
mm_obj_dbg (self, " device: %s", g_udev_device_get_sysfs_path (self->priv->physdev));
if (self->priv->driver)
mm_obj_dbg (self, " driver: %s", self->priv->driver);
if (self->priv->vendor)
mm_obj_dbg (self, " vendor: %04x", self->priv->vendor);
if (self->priv->product)
mm_obj_dbg (self, " product: %04x", self->priv->product);
if (self->priv->subsystem_vendor)
mm_obj_dbg (self, " subsystem vendor: %04x", self->priv->subsystem_vendor);
if (self->priv->subsystem_device)
mm_obj_dbg (self, " subsystem device: %04x", self->priv->subsystem_device);
if (self->priv->revision)
mm_obj_dbg (self, " revision: %04x", self->priv->revision);
}
/*****************************************************************************/
static const gchar *
kernel_device_get_subsystem (MMKernelDevice *_self)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
if (self->priv->device)
return g_udev_device_get_subsystem (self->priv->device);
g_assert (self->priv->properties);
return mm_kernel_event_properties_get_subsystem (self->priv->properties);
}
static const gchar *
kernel_device_get_name (MMKernelDevice *_self)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
if (self->priv->device)
return g_udev_device_get_name (self->priv->device);
g_assert (self->priv->properties);
return mm_kernel_event_properties_get_name (self->priv->properties);
}
static const gchar *
kernel_device_get_driver (MMKernelDevice *self)
{
return MM_KERNEL_DEVICE_UDEV (self)->priv->driver;
}
static const gchar *
kernel_device_get_sysfs_path (MMKernelDevice *_self)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
return (self->priv->device ?
g_udev_device_get_sysfs_path (self->priv->device) :
NULL);
}
static const gchar *
kernel_device_get_wwandev_sysfs_path (MMKernelDevice *_self)
{
g_autoptr(GUdevDevice) parent = NULL;
MMKernelDeviceUdev *self;
const gchar *subsys;
self = MM_KERNEL_DEVICE_UDEV (_self);
parent = g_udev_device_get_parent (self->priv->device);
if (!parent)
return NULL;
subsys = g_udev_device_get_subsystem (parent);
if (!subsys || g_strcmp0 (subsys, "wwan"))
return NULL;
return g_udev_device_get_sysfs_path (parent);
}
static const gchar *
kernel_device_get_physdev_uid (MMKernelDevice *_self)
{
MMKernelDeviceUdev *self;
const gchar *uid = NULL;
self = MM_KERNEL_DEVICE_UDEV (_self);
/* Prefer the one coming in the properties, if any */
if (self->priv->properties) {
if ((uid = mm_kernel_event_properties_get_uid (self->priv->properties)) != NULL)
return uid;
}
/* Try to load from properties set on the physical device */
if ((uid = mm_kernel_device_get_global_property (_self, ID_MM_PHYSDEV_UID)) != NULL)
return uid;
/* Use physical device sysfs path, if any */
if (self->priv->physdev && (uid = g_udev_device_get_sysfs_path (self->priv->physdev)) != NULL)
return uid;
/* If there is no physical device sysfs path, use the device sysfs itself */
g_assert (self->priv->device);
return g_udev_device_get_sysfs_path (self->priv->device);
}
static guint16
kernel_device_get_physdev_vid (MMKernelDevice *self)
{
return MM_KERNEL_DEVICE_UDEV (self)->priv->vendor;
}
static guint16
kernel_device_get_physdev_pid (MMKernelDevice *self)
{
return MM_KERNEL_DEVICE_UDEV (self)->priv->product;
}
static guint16
kernel_device_get_physdev_subsystem_vid (MMKernelDevice *self)
{
return MM_KERNEL_DEVICE_UDEV (self)->priv->subsystem_vendor;
}
static guint16
kernel_device_get_physdev_subsystem_pid (MMKernelDevice *self)
{
return MM_KERNEL_DEVICE_UDEV (self)->priv->subsystem_device;
}
static guint16
kernel_device_get_physdev_revision (MMKernelDevice *self)
{
return MM_KERNEL_DEVICE_UDEV (self)->priv->revision;
}
static const gchar *
kernel_device_get_physdev_sysfs_path (MMKernelDevice *_self)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
return (self->priv->physdev ? g_udev_device_get_sysfs_path (self->priv->physdev) : NULL);
}
static const gchar *
kernel_device_get_physdev_subsystem (MMKernelDevice *_self)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
return (self->priv->physdev ? g_udev_device_get_subsystem (self->priv->physdev) : NULL);
}
static const gchar *
kernel_device_get_physdev_manufacturer (MMKernelDevice *_self)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
return (self->priv->physdev ? g_udev_device_get_sysfs_attr (self->priv->physdev, "manufacturer") : NULL);
}
static const gchar *
kernel_device_get_physdev_product (MMKernelDevice *_self)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
return (self->priv->physdev ? g_udev_device_get_sysfs_attr (self->priv->physdev, "product") : NULL);
}
static gint
kernel_device_get_interface_number (MMKernelDevice *_self)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
return (self->priv->interface ? (gint) udev_device_get_sysfs_attr_as_hex (self->priv->interface, "bInterfaceNumber") : -1);
}
static gint
kernel_device_get_interface_class (MMKernelDevice *_self)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
return (self->priv->interface ? (gint) udev_device_get_sysfs_attr_as_hex (self->priv->interface, "bInterfaceClass") : -1);
}
static gint
kernel_device_get_interface_subclass (MMKernelDevice *_self)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
return (self->priv->interface ? (gint) udev_device_get_sysfs_attr_as_hex (self->priv->interface, "bInterfaceSubClass") : -1);
}
static gint
kernel_device_get_interface_protocol (MMKernelDevice *_self)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
return (self->priv->interface ? (gint) udev_device_get_sysfs_attr_as_hex (self->priv->interface, "bInterfaceProtocol") : -1);
}
static const gchar *
kernel_device_get_interface_sysfs_path (MMKernelDevice *_self)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
return (self->priv->interface ? g_udev_device_get_sysfs_path (self->priv->interface) : NULL);
}
static const gchar *
kernel_device_get_interface_description (MMKernelDevice *_self)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
return (self->priv->interface ? g_udev_device_get_sysfs_attr (self->priv->interface, "interface") : NULL);
}
static gboolean
kernel_device_cmp (MMKernelDevice *_a,
MMKernelDevice *_b)
{
MMKernelDeviceUdev *a;
MMKernelDeviceUdev *b;
a = MM_KERNEL_DEVICE_UDEV (_a);
b = MM_KERNEL_DEVICE_UDEV (_b);
if (a->priv->device && b->priv->device) {
if (g_udev_device_has_property (a->priv->device, "DEVPATH_OLD") &&
g_str_has_suffix (g_udev_device_get_sysfs_path (b->priv->device),
g_udev_device_get_property (a->priv->device, "DEVPATH_OLD")))
return TRUE;
if (g_udev_device_has_property (b->priv->device, "DEVPATH_OLD") &&
g_str_has_suffix (g_udev_device_get_sysfs_path (a->priv->device),
g_udev_device_get_property (b->priv->device, "DEVPATH_OLD")))
return TRUE;
return !g_strcmp0 (g_udev_device_get_sysfs_path (a->priv->device), g_udev_device_get_sysfs_path (b->priv->device));
}
return (!g_strcmp0 (mm_kernel_device_get_subsystem (_a), mm_kernel_device_get_subsystem (_b)) &&
!g_strcmp0 (mm_kernel_device_get_name (_a), mm_kernel_device_get_name (_b)));
}
static gboolean
kernel_device_has_property (MMKernelDevice *_self,
const gchar *property)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
return (self->priv->device ? g_udev_device_has_property (self->priv->device, property) : FALSE);
}
static const gchar *
kernel_device_get_property (MMKernelDevice *_self,
const gchar *property)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
return (self->priv->device ? g_udev_device_get_property (self->priv->device, property) : NULL);
}
static gboolean
kernel_device_has_global_property (MMKernelDevice *_self,
const gchar *property)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
if (self->priv->physdev && g_udev_device_has_property (self->priv->physdev, property))
return TRUE;
return kernel_device_has_property (_self, property);
}
static const gchar *
kernel_device_get_global_property (MMKernelDevice *_self,
const gchar *property)
{
MMKernelDeviceUdev *self;
const gchar *str;
self = MM_KERNEL_DEVICE_UDEV (_self);
if (self->priv->physdev &&
g_udev_device_has_property (self->priv->physdev, property) &&
(str = g_udev_device_get_property (self->priv->physdev, property)) != NULL)
return str;
return kernel_device_get_property (_self, property);
}
/*****************************************************************************/
static gboolean
kernel_device_has_attribute (MMKernelDevice *_self,
const gchar *attribute)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
if (!self->priv->device)
return FALSE;
return g_udev_device_has_sysfs_attr (self->priv->device, attribute);
}
static const gchar *
kernel_device_get_attribute (MMKernelDevice *_self,
const gchar *attribute)
{
MMKernelDeviceUdev *self;
self = MM_KERNEL_DEVICE_UDEV (_self);
if (!self->priv->device)
return NULL;
return g_udev_device_get_sysfs_attr (self->priv->device, attribute);
}
/*****************************************************************************/
MMKernelDevice *
mm_kernel_device_udev_new (GUdevClient *udev_client,
GUdevDevice *udev_device)
{
GError *error = NULL;
MMKernelDevice *self;
self = MM_KERNEL_DEVICE (g_initable_new (MM_TYPE_KERNEL_DEVICE_UDEV,
NULL,
&error,
"udev-client", udev_client,
"udev-device", udev_device,
NULL));
g_assert_no_error (error);
return self;
}
/*****************************************************************************/
MMKernelDevice *
mm_kernel_device_udev_new_from_properties (GUdevClient *udev_client,
MMKernelEventProperties *props,
GError **error)
{
return MM_KERNEL_DEVICE (g_initable_new (MM_TYPE_KERNEL_DEVICE_UDEV,
NULL,
error,
"udev-client", udev_client,
"properties", props,
NULL));
}
/*****************************************************************************/
static void
mm_kernel_device_udev_init (MMKernelDeviceUdev *self)
{
/* Initialize private data */
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_KERNEL_DEVICE_UDEV, MMKernelDeviceUdevPrivate);
}
static void
set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MMKernelDeviceUdev *self = MM_KERNEL_DEVICE_UDEV (object);
switch (prop_id) {
case PROP_UDEV_CLIENT:
g_assert (!self->priv->client);
self->priv->client = g_value_dup_object (value);
break;
case PROP_UDEV_DEVICE:
g_assert (!self->priv->device);
self->priv->device = g_value_dup_object (value);
break;
case PROP_PROPERTIES:
g_assert (!self->priv->properties);
self->priv->properties = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MMKernelDeviceUdev *self = MM_KERNEL_DEVICE_UDEV (object);
switch (prop_id) {
case PROP_UDEV_CLIENT:
g_value_set_object (value, self->priv->client);
break;
case PROP_UDEV_DEVICE:
g_value_set_object (value, self->priv->device);
break;
case PROP_PROPERTIES:
g_value_set_object (value, self->priv->properties);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
MMKernelDeviceUdev *self = MM_KERNEL_DEVICE_UDEV (initable);
const gchar *subsystem;
const gchar *name;
if (!self->priv->client) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"missing client in kernel device");
return FALSE;
}
/* When created from a GUdevDevice, we're done */
if (self->priv->device) {
preload_contents (self);
return TRUE;
}
/* Otherwise, we do need properties with subsystem and name */
if (!self->priv->properties) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"missing properties in kernel device");
return FALSE;
}
subsystem = mm_kernel_event_properties_get_subsystem (self->priv->properties);
if (!subsystem) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"subsystem is mandatory in kernel device");
return FALSE;
}
name = mm_kernel_event_properties_get_name (self->priv->properties);
if (!mm_kernel_device_get_name (MM_KERNEL_DEVICE (self))) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"name is mandatory in kernel device");
return FALSE;
}
/* On remove events, we don't look for the GUdevDevice */
if (g_strcmp0 (mm_kernel_event_properties_get_action (self->priv->properties), "remove")) {
g_assert (!self->priv->device);
self->priv->device = g_udev_client_query_by_subsystem_and_name (self->priv->client, subsystem, name);
if (!self->priv->device) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
"device %s/%s not found",
subsystem,
name);
return FALSE;
}
}
if (self->priv->device)
preload_contents (self);
return TRUE;
}
static void
dispose (GObject *object)
{
MMKernelDeviceUdev *self = MM_KERNEL_DEVICE_UDEV (object);
g_clear_pointer (&self->priv->driver, g_free);
g_clear_object (&self->priv->physdev);
g_clear_object (&self->priv->interface);
g_clear_object (&self->priv->device);
g_clear_object (&self->priv->client);
g_clear_object (&self->priv->properties);
G_OBJECT_CLASS (mm_kernel_device_udev_parent_class)->dispose (object);
}
static void
initable_iface_init (GInitableIface *iface)
{
iface->init = initable_init;
}
static void
mm_kernel_device_udev_class_init (MMKernelDeviceUdevClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MMKernelDeviceClass *kernel_device_class = MM_KERNEL_DEVICE_CLASS (klass);
g_type_class_add_private (object_class, sizeof (MMKernelDeviceUdevPrivate));
object_class->dispose = dispose;
object_class->get_property = get_property;
object_class->set_property = set_property;
kernel_device_class->get_subsystem = kernel_device_get_subsystem;
kernel_device_class->get_name = kernel_device_get_name;
kernel_device_class->get_driver = kernel_device_get_driver;
kernel_device_class->get_sysfs_path = kernel_device_get_sysfs_path;
kernel_device_class->get_wwandev_sysfs_path = kernel_device_get_wwandev_sysfs_path;
kernel_device_class->get_physdev_uid = kernel_device_get_physdev_uid;
kernel_device_class->get_physdev_vid = kernel_device_get_physdev_vid;
kernel_device_class->get_physdev_pid = kernel_device_get_physdev_pid;
kernel_device_class->get_physdev_subsystem_vid = kernel_device_get_physdev_subsystem_vid;
kernel_device_class->get_physdev_subsystem_pid = kernel_device_get_physdev_subsystem_pid;
kernel_device_class->get_physdev_revision = kernel_device_get_physdev_revision;
kernel_device_class->get_physdev_sysfs_path = kernel_device_get_physdev_sysfs_path;
kernel_device_class->get_physdev_subsystem = kernel_device_get_physdev_subsystem;
kernel_device_class->get_physdev_manufacturer = kernel_device_get_physdev_manufacturer;
kernel_device_class->get_physdev_product = kernel_device_get_physdev_product;
kernel_device_class->get_interface_number = kernel_device_get_interface_number;
kernel_device_class->get_interface_class = kernel_device_get_interface_class;
kernel_device_class->get_interface_subclass = kernel_device_get_interface_subclass;
kernel_device_class->get_interface_protocol = kernel_device_get_interface_protocol;
kernel_device_class->get_interface_sysfs_path = kernel_device_get_interface_sysfs_path;
kernel_device_class->get_interface_description = kernel_device_get_interface_description;
kernel_device_class->cmp = kernel_device_cmp;
kernel_device_class->has_property = kernel_device_has_property;
kernel_device_class->get_property = kernel_device_get_property;
kernel_device_class->has_global_property = kernel_device_has_global_property;
kernel_device_class->get_global_property = kernel_device_get_global_property;
kernel_device_class->has_attribute = kernel_device_has_attribute;
kernel_device_class->get_attribute = kernel_device_get_attribute;
properties[PROP_UDEV_DEVICE] =
g_param_spec_object ("udev-device",
"udev device",
"Device object as reported by GUdev",
G_UDEV_TYPE_DEVICE,
G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_UDEV_DEVICE, properties[PROP_UDEV_DEVICE]);
properties[PROP_UDEV_CLIENT] =
g_param_spec_object ("udev-client",
"udev client",
"GUdev client",
G_UDEV_TYPE_CLIENT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class, PROP_UDEV_CLIENT, properties[PROP_UDEV_CLIENT]);
properties[PROP_PROPERTIES] =
g_param_spec_object ("properties",
"Properties",
"Generic kernel event properties",
MM_TYPE_KERNEL_EVENT_PROPERTIES,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class, PROP_PROPERTIES, properties[PROP_PROPERTIES]);
}