
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.
624 lines
21 KiB
C
624 lines
21 KiB
C
/* -*- 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]);
|
|
}
|