core: new kernel device object instead of an explicit GUdevDevice
Instead of relying constantly on GUdevDevice objects reported by GUdev, we now use a new generic object (MMKernelDevice) for which we provide an initial GUdev based backend.
This commit is contained in:
623
src/kerneldevice/mm-kernel-device-udev.c
Normal file
623
src/kerneldevice/mm-kernel-device-udev.c
Normal file
@@ -0,0 +1,623 @@
|
||||
/* -*- 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-kernel-device-udev.h"
|
||||
#include "mm-log.h"
|
||||
|
||||
G_DEFINE_TYPE (MMKernelDeviceUdev, mm_kernel_device_udev, MM_TYPE_KERNEL_DEVICE)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_UDEV_DEVICE,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
static GParamSpec *properties[PROP_LAST];
|
||||
|
||||
struct _MMKernelDeviceUdevPrivate {
|
||||
GUdevDevice *device;
|
||||
GUdevDevice *parent;
|
||||
GUdevDevice *physdev;
|
||||
guint16 vendor;
|
||||
guint16 product;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
get_device_ids (GUdevDevice *device,
|
||||
guint16 *vendor,
|
||||
guint16 *product)
|
||||
{
|
||||
GUdevDevice *parent = NULL;
|
||||
const gchar *vid = NULL, *pid = NULL, *parent_subsys;
|
||||
gboolean success = FALSE;
|
||||
char *pci_vid = NULL, *pci_pid = NULL;
|
||||
|
||||
parent = g_udev_device_get_parent (device);
|
||||
if (parent) {
|
||||
parent_subsys = g_udev_device_get_subsystem (parent);
|
||||
if (parent_subsys) {
|
||||
if (g_str_equal (parent_subsys, "bluetooth")) {
|
||||
/* Bluetooth devices report the VID/PID of the BT adapter here,
|
||||
* which isn't really what we want. Just return null IDs instead.
|
||||
*/
|
||||
success = TRUE;
|
||||
goto out;
|
||||
} else if (g_str_equal (parent_subsys, "pcmcia")) {
|
||||
/* For PCMCIA devices we need to grab the PCMCIA subsystem's
|
||||
* manfid and cardid, since any IDs on the tty device itself
|
||||
* may be from PCMCIA controller or something else.
|
||||
*/
|
||||
vid = g_udev_device_get_sysfs_attr (parent, "manf_id");
|
||||
pid = g_udev_device_get_sysfs_attr (parent, "card_id");
|
||||
if (!vid || !pid)
|
||||
goto out;
|
||||
} else if (g_str_equal (parent_subsys, "platform")) {
|
||||
/* Platform devices don't usually have a VID/PID */
|
||||
success = TRUE;
|
||||
goto out;
|
||||
} else if (g_str_has_prefix (parent_subsys, "usb") &&
|
||||
(!g_strcmp0 (g_udev_device_get_driver (parent), "qmi_wwan") ||
|
||||
!g_strcmp0 (g_udev_device_get_driver (parent), "cdc_mbim"))) {
|
||||
/* Need to look for vendor/product in the parent of the QMI/MBIM device */
|
||||
GUdevDevice *qmi_parent;
|
||||
|
||||
qmi_parent = g_udev_device_get_parent (parent);
|
||||
if (qmi_parent) {
|
||||
vid = g_udev_device_get_property (qmi_parent, "ID_VENDOR_ID");
|
||||
pid = g_udev_device_get_property (qmi_parent, "ID_MODEL_ID");
|
||||
g_object_unref (qmi_parent);
|
||||
}
|
||||
} else if (g_str_equal (parent_subsys, "pci")) {
|
||||
const char *pci_id;
|
||||
|
||||
/* We can't always rely on the model + vendor showing up on
|
||||
* the PCI device's child, so look at the PCI parent. PCI_ID
|
||||
* has the format "1931:000C".
|
||||
*/
|
||||
pci_id = g_udev_device_get_property (parent, "PCI_ID");
|
||||
if (pci_id && strlen (pci_id) == 9 && pci_id[4] == ':') {
|
||||
vid = pci_vid = g_strdup (pci_id);
|
||||
pci_vid[4] = '\0';
|
||||
pid = pci_pid = g_strdup (pci_id + 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!vid)
|
||||
vid = g_udev_device_get_property (device, "ID_VENDOR_ID");
|
||||
if (!vid)
|
||||
goto out;
|
||||
|
||||
if (strncmp (vid, "0x", 2) == 0)
|
||||
vid += 2;
|
||||
if (strlen (vid) != 4)
|
||||
goto out;
|
||||
|
||||
if (vendor) {
|
||||
*vendor = (guint16) (mm_utils_hex2byte (vid + 2) & 0xFF);
|
||||
*vendor |= (guint16) ((mm_utils_hex2byte (vid) & 0xFF) << 8);
|
||||
}
|
||||
|
||||
if (!pid)
|
||||
pid = g_udev_device_get_property (device, "ID_MODEL_ID");
|
||||
if (!pid) {
|
||||
*vendor = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strncmp (pid, "0x", 2) == 0)
|
||||
pid += 2;
|
||||
if (strlen (pid) != 4) {
|
||||
*vendor = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (product) {
|
||||
*product = (guint16) (mm_utils_hex2byte (pid + 2) & 0xFF);
|
||||
*product |= (guint16) ((mm_utils_hex2byte (pid) & 0xFF) << 8);
|
||||
}
|
||||
|
||||
success = TRUE;
|
||||
|
||||
out:
|
||||
if (parent)
|
||||
g_object_unref (parent);
|
||||
g_free (pci_vid);
|
||||
g_free (pci_pid);
|
||||
return success;
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_device_ids (MMKernelDeviceUdev *self)
|
||||
{
|
||||
if (self->priv->vendor || self->priv->product)
|
||||
return;
|
||||
|
||||
if (!get_device_ids (self->priv->device, &self->priv->vendor, &self->priv->product))
|
||||
mm_dbg ("(%s/%s) could not get vendor/product ID",
|
||||
g_udev_device_get_subsystem (self->priv->device),
|
||||
g_udev_device_get_name (self->priv->device));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static GUdevDevice *
|
||||
find_physical_gudevdevice (GUdevDevice *child)
|
||||
{
|
||||
GUdevDevice *iter, *old = NULL;
|
||||
GUdevDevice *physdev = NULL;
|
||||
const char *subsys, *type, *name;
|
||||
guint32 i = 0;
|
||||
gboolean is_usb = FALSE, is_pci = FALSE, is_pcmcia = FALSE, is_platform = FALSE;
|
||||
gboolean is_pnp = FALSE;
|
||||
|
||||
g_return_val_if_fail (child != NULL, NULL);
|
||||
|
||||
/* Bluetooth rfcomm devices are "virtual" and don't necessarily have
|
||||
* parents at all.
|
||||
*/
|
||||
name = g_udev_device_get_name (child);
|
||||
if (name && strncmp (name, "rfcomm", 6) == 0)
|
||||
return g_object_ref (child);
|
||||
|
||||
iter = g_object_ref (child);
|
||||
while (iter && i++ < 8) {
|
||||
subsys = g_udev_device_get_subsystem (iter);
|
||||
if (subsys) {
|
||||
if (is_usb || g_str_has_prefix (subsys, "usb")) {
|
||||
is_usb = TRUE;
|
||||
type = g_udev_device_get_devtype (iter);
|
||||
if (type && !strcmp (type, "usb_device")) {
|
||||
physdev = iter;
|
||||
break;
|
||||
}
|
||||
} else if (is_pcmcia || !strcmp (subsys, "pcmcia")) {
|
||||
GUdevDevice *pcmcia_parent;
|
||||
const char *tmp_subsys;
|
||||
|
||||
is_pcmcia = 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.
|
||||
*/
|
||||
pcmcia_parent = g_udev_device_get_parent (iter);
|
||||
if (pcmcia_parent) {
|
||||
tmp_subsys = g_udev_device_get_subsystem (pcmcia_parent);
|
||||
if (tmp_subsys && strcmp (tmp_subsys, "pcmcia"))
|
||||
physdev = iter;
|
||||
g_object_unref (pcmcia_parent);
|
||||
if (physdev)
|
||||
break;
|
||||
}
|
||||
} else if (is_platform || !strcmp (subsys, "platform")) {
|
||||
/* Take the first platform parent as the physical device */
|
||||
is_platform = TRUE;
|
||||
physdev = iter;
|
||||
break;
|
||||
} else if (is_pci || !strcmp (subsys, "pci")) {
|
||||
is_pci = TRUE;
|
||||
physdev = iter;
|
||||
break;
|
||||
} else if (is_pnp || !strcmp (subsys, "pnp")) {
|
||||
is_pnp = TRUE;
|
||||
physdev = iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
old = iter;
|
||||
iter = g_udev_device_get_parent (old);
|
||||
g_object_unref (old);
|
||||
}
|
||||
|
||||
return physdev;
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_physdev (MMKernelDeviceUdev *self)
|
||||
{
|
||||
if (self->priv->physdev)
|
||||
return;
|
||||
self->priv->physdev = find_physical_gudevdevice (self->priv->device);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static const gchar *
|
||||
kernel_device_get_subsystem (MMKernelDevice *self)
|
||||
{
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (self), NULL);
|
||||
|
||||
return g_udev_device_get_subsystem (MM_KERNEL_DEVICE_UDEV (self)->priv->device);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
kernel_device_get_name (MMKernelDevice *self)
|
||||
{
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (self), NULL);
|
||||
|
||||
return g_udev_device_get_name (MM_KERNEL_DEVICE_UDEV (self)->priv->device);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
kernel_device_get_driver (MMKernelDevice *_self)
|
||||
{
|
||||
MMKernelDeviceUdev *self;
|
||||
const gchar *driver, *subsys, *name;
|
||||
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), NULL);
|
||||
|
||||
self = MM_KERNEL_DEVICE_UDEV (_self);
|
||||
|
||||
driver = g_udev_device_get_driver (self->priv->device);
|
||||
if (!driver) {
|
||||
GUdevDevice *parent;
|
||||
|
||||
parent = g_udev_device_get_parent (self->priv->device);
|
||||
if (parent)
|
||||
driver = g_udev_device_get_driver (parent);
|
||||
|
||||
/* Check for bluetooth; it's driver is a bunch of levels up so we
|
||||
* just check for the subsystem of the parent being bluetooth.
|
||||
*/
|
||||
if (!driver && parent) {
|
||||
subsys = g_udev_device_get_subsystem (parent);
|
||||
if (subsys && !strcmp (subsys, "bluetooth"))
|
||||
driver = "bluetooth";
|
||||
}
|
||||
|
||||
if (parent)
|
||||
g_object_unref (parent);
|
||||
}
|
||||
|
||||
/* Newer kernels don't set up the rfcomm port parent in sysfs,
|
||||
* so we must infer it from the device name.
|
||||
*/
|
||||
name = g_udev_device_get_name (self->priv->device);
|
||||
if (!driver && strncmp (name, "rfcomm", 6) == 0)
|
||||
driver = "bluetooth";
|
||||
|
||||
/* Note: may return NULL! */
|
||||
return driver;
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
kernel_device_get_sysfs_path (MMKernelDevice *self)
|
||||
{
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE (self), NULL);
|
||||
|
||||
return g_udev_device_get_sysfs_path (MM_KERNEL_DEVICE_UDEV (self)->priv->device);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
kernel_device_get_physdev_uid (MMKernelDevice *_self)
|
||||
{
|
||||
MMKernelDeviceUdev *self;
|
||||
const gchar *uid = NULL;
|
||||
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), NULL);
|
||||
|
||||
self = MM_KERNEL_DEVICE_UDEV (_self);
|
||||
ensure_physdev (self);
|
||||
|
||||
if (!self->priv->physdev)
|
||||
return NULL;
|
||||
|
||||
uid = g_udev_device_get_property (self->priv->physdev, "ID_MM_PHYSDEV_UID");
|
||||
if (!uid)
|
||||
uid = g_udev_device_get_sysfs_path (self->priv->physdev);
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
static guint16
|
||||
kernel_device_get_physdev_vid (MMKernelDevice *_self)
|
||||
{
|
||||
MMKernelDeviceUdev *self;
|
||||
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), 0);
|
||||
|
||||
self = MM_KERNEL_DEVICE_UDEV (_self);
|
||||
ensure_device_ids (self);
|
||||
return self->priv->vendor;
|
||||
}
|
||||
|
||||
static guint16
|
||||
kernel_device_get_physdev_pid (MMKernelDevice *_self)
|
||||
{
|
||||
MMKernelDeviceUdev *self;
|
||||
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), 0);
|
||||
|
||||
self = MM_KERNEL_DEVICE_UDEV (_self);
|
||||
ensure_device_ids (self);
|
||||
return self->priv->product;
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
kernel_device_get_parent_sysfs_path (MMKernelDevice *_self)
|
||||
{
|
||||
MMKernelDeviceUdev *self;
|
||||
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), 0);
|
||||
|
||||
self = MM_KERNEL_DEVICE_UDEV (_self);
|
||||
if (!self->priv->parent)
|
||||
self->priv->parent = g_udev_device_get_parent (self->priv->device);
|
||||
return (self->priv->parent ? g_udev_device_get_sysfs_path (self->priv->parent) : NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
kernel_device_is_candidate (MMKernelDevice *_self,
|
||||
gboolean manual_scan)
|
||||
{
|
||||
MMKernelDeviceUdev *self;
|
||||
const gchar *physdev_subsys;
|
||||
const gchar *name;
|
||||
const gchar *subsys;
|
||||
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), FALSE);
|
||||
|
||||
self = MM_KERNEL_DEVICE_UDEV (_self);
|
||||
|
||||
name = g_udev_device_get_name (self->priv->device);
|
||||
subsys = g_udev_device_get_subsystem (self->priv->device);
|
||||
|
||||
/* ignore VTs */
|
||||
if (strncmp (name, "tty", 3) == 0 && g_ascii_isdigit (name[3]))
|
||||
return FALSE;
|
||||
|
||||
/* Ignore devices that aren't completely configured by udev yet. If
|
||||
* ModemManager is started in parallel with udev, explicitly requesting
|
||||
* devices may return devices for which not all udev rules have yet been
|
||||
* applied (a bug in udev/gudev). Since we often need those rules to match
|
||||
* the device to a specific ModemManager driver, we need to ensure that all
|
||||
* rules have been processed before handling a device.
|
||||
*
|
||||
* The udev tag applies to each port in a device. In other words, the flag
|
||||
* may be set in some ports, but not in others */
|
||||
if (!g_udev_device_get_property_as_boolean (self->priv->device, "ID_MM_CANDIDATE"))
|
||||
return FALSE;
|
||||
|
||||
/* Load physical device. If there is no physical device, we don't process
|
||||
* the device. */
|
||||
ensure_physdev (self);
|
||||
if (!self->priv->physdev) {
|
||||
/* Log about it, but filter out some common ports that we know don't have
|
||||
* anything to do with mobile broadband.
|
||||
*/
|
||||
if ( strcmp (name, "console")
|
||||
&& strcmp (name, "ptmx")
|
||||
&& strcmp (name, "lo")
|
||||
&& strcmp (name, "tty")
|
||||
&& !strstr (name, "virbr"))
|
||||
mm_dbg ("(%s/%s): could not get port's parent device", subsys, name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* The blacklist applies to the device as a whole, and therefore the flag
|
||||
* will be applied always in the physical device, not in each port. */
|
||||
if (g_udev_device_get_property_as_boolean (self->priv->physdev, "ID_MM_DEVICE_IGNORE")) {
|
||||
mm_dbg ("(%s/%s): device is blacklisted", subsys, name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Is the device in the manual-only greylist? If so, return if this is an
|
||||
* automatic scan. */
|
||||
if (!manual_scan && g_udev_device_get_property_as_boolean (self->priv->physdev, "ID_MM_DEVICE_MANUAL_SCAN_ONLY")) {
|
||||
mm_dbg ("(%s/%s): device probed only in manual scan", subsys, name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* If the physdev is a 'platform' or 'pnp' device that's not whitelisted, ignore it */
|
||||
physdev_subsys = g_udev_device_get_subsystem (self->priv->physdev);
|
||||
if ((!g_strcmp0 (physdev_subsys, "platform") || !g_strcmp0 (physdev_subsys, "pnp")) &&
|
||||
(!g_udev_device_get_property_as_boolean (self->priv->physdev, "ID_MM_PLATFORM_DRIVER_PROBE"))) {
|
||||
mm_dbg ("(%s/%s): port's parent platform driver is not whitelisted", subsys, name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
kernel_device_cmp (MMKernelDevice *_a,
|
||||
MMKernelDevice *_b)
|
||||
{
|
||||
MMKernelDeviceUdev *a;
|
||||
MMKernelDeviceUdev *b;
|
||||
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_a), FALSE);
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_b), FALSE);
|
||||
|
||||
a = MM_KERNEL_DEVICE_UDEV (_a);
|
||||
b = MM_KERNEL_DEVICE_UDEV (_b);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
kernel_device_has_property (MMKernelDevice *_self,
|
||||
const gchar *property)
|
||||
{
|
||||
MMKernelDeviceUdev *self;
|
||||
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), FALSE);
|
||||
|
||||
self = MM_KERNEL_DEVICE_UDEV (_self);
|
||||
return g_udev_device_has_property (self->priv->device, property);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
kernel_device_get_property (MMKernelDevice *_self,
|
||||
const gchar *property)
|
||||
{
|
||||
MMKernelDeviceUdev *self;
|
||||
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), NULL);
|
||||
|
||||
self = MM_KERNEL_DEVICE_UDEV (_self);
|
||||
return g_udev_device_get_property (self->priv->device, property);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
kernel_device_get_property_as_boolean (MMKernelDevice *_self,
|
||||
const gchar *property)
|
||||
{
|
||||
MMKernelDeviceUdev *self;
|
||||
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), FALSE);
|
||||
|
||||
self = MM_KERNEL_DEVICE_UDEV (_self);
|
||||
return g_udev_device_get_property_as_boolean (self->priv->device, property);
|
||||
}
|
||||
|
||||
static gint
|
||||
kernel_device_get_property_as_int (MMKernelDevice *_self,
|
||||
const gchar *property)
|
||||
{
|
||||
MMKernelDeviceUdev *self;
|
||||
|
||||
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), -1);
|
||||
|
||||
self = MM_KERNEL_DEVICE_UDEV (_self);
|
||||
return g_udev_device_get_property_as_int (self->priv->device, property);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMKernelDevice *
|
||||
mm_kernel_device_udev_new (GUdevDevice *udev_device)
|
||||
{
|
||||
g_return_val_if_fail (G_UDEV_IS_DEVICE (udev_device), NULL);
|
||||
|
||||
return MM_KERNEL_DEVICE (g_object_new (MM_TYPE_KERNEL_DEVICE_UDEV,
|
||||
"udev-device", udev_device,
|
||||
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_DEVICE:
|
||||
g_assert (!self->priv->device);
|
||||
self->priv->device = 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_DEVICE:
|
||||
g_value_set_object (value, self->priv->device);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
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->device);
|
||||
|
||||
G_OBJECT_CLASS (mm_kernel_device_udev_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
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_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_parent_sysfs_path = kernel_device_get_parent_sysfs_path;
|
||||
kernel_device_class->is_candidate = kernel_device_is_candidate;
|
||||
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->get_property_as_boolean = kernel_device_get_property_as_boolean;
|
||||
kernel_device_class->get_property_as_int = kernel_device_get_property_as_int;
|
||||
|
||||
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_PARAM_CONSTRUCT_ONLY);
|
||||
g_object_class_install_property (object_class, PROP_UDEV_DEVICE, properties[PROP_UDEV_DEVICE]);
|
||||
}
|
Reference in New Issue
Block a user