Blame src/mm-device.c

Packit Service 8101fe
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
Packit Service 8101fe
/*
Packit Service 8101fe
 * This program is free software; you can redistribute it and/or modify
Packit Service 8101fe
 * it under the terms of the GNU General Public License as published by
Packit Service 8101fe
 * the Free Software Foundation; either version 2 of the License, or
Packit Service 8101fe
 * (at your option) any later version.
Packit Service 8101fe
 *
Packit Service 8101fe
 * This program is distributed in the hope that it will be useful,
Packit Service 8101fe
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 8101fe
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 8101fe
 * GNU General Public License for more details:
Packit Service 8101fe
 *
Packit Service 8101fe
 * Copyright (C) 2012 Google, Inc.
Packit Service 8101fe
 */
Packit Service 8101fe
Packit Service 8101fe
#include <config.h>
Packit Service 8101fe
#include <stdio.h>
Packit Service 8101fe
#include <stdlib.h>
Packit Service 8101fe
#include <unistd.h>
Packit Service 8101fe
#include <string.h>
Packit Service 8101fe
Packit Service 8101fe
#include <ModemManager.h>
Packit Service 8101fe
#define _LIBMM_INSIDE_MM
Packit Service 8101fe
#include <libmm-glib.h>
Packit Service 8101fe
Packit Service 8101fe
#include "mm-device.h"
Packit Service 8101fe
#include "mm-plugin.h"
Packit Service 8101fe
#include "mm-log.h"
Packit Service 8101fe
Packit Service 8101fe
G_DEFINE_TYPE (MMDevice, mm_device, G_TYPE_OBJECT);
Packit Service 8101fe
Packit Service 8101fe
enum {
Packit Service 8101fe
    PROP_0,
Packit Service 8101fe
    PROP_UID,
Packit Service 8101fe
    PROP_PLUGIN,
Packit Service 8101fe
    PROP_MODEM,
Packit Service 8101fe
    PROP_HOTPLUGGED,
Packit Service 8101fe
    PROP_VIRTUAL,
Packit Service 8101fe
    PROP_INHIBITED,
Packit Service 8101fe
    PROP_LAST
Packit Service 8101fe
};
Packit Service 8101fe
Packit Service 8101fe
enum {
Packit Service 8101fe
    SIGNAL_PORT_GRABBED,
Packit Service 8101fe
    SIGNAL_PORT_RELEASED,
Packit Service 8101fe
    SIGNAL_LAST
Packit Service 8101fe
};
Packit Service 8101fe
Packit Service 8101fe
static GParamSpec *properties[PROP_LAST];
Packit Service 8101fe
static guint signals[SIGNAL_LAST];
Packit Service 8101fe
Packit Service 8101fe
struct _MMDevicePrivate {
Packit Service 8101fe
    /* Whether the device is real or virtual */
Packit Service 8101fe
    gboolean virtual;
Packit Service 8101fe
Packit Service 8101fe
    /* Unique id */
Packit Service 8101fe
    gchar *uid;
Packit Service 8101fe
Packit Service 8101fe
    /* If USB, device vid/pid */
Packit Service 8101fe
    guint16 vendor;
Packit Service 8101fe
    guint16 product;
Packit Service 8101fe
Packit Service 8101fe
    /* Kernel drivers managing this device */
Packit Service 8101fe
    gchar **drivers;
Packit Service 8101fe
Packit Service 8101fe
    /* Best plugin to manage this device */
Packit Service 8101fe
    MMPlugin *plugin;
Packit Service 8101fe
Packit Service 8101fe
    /* Lists of port probes in the device */
Packit Service 8101fe
    GList *port_probes;
Packit Service 8101fe
    GList *ignored_port_probes;
Packit Service 8101fe
Packit Service 8101fe
    /* The Modem object for this device */
Packit Service 8101fe
    MMBaseModem *modem;
Packit Service 8101fe
    gulong       modem_valid_id;
Packit Service 8101fe
Packit Service 8101fe
    /* When exported, a reference to the object manager */
Packit Service 8101fe
    GDBusObjectManagerServer *object_manager;
Packit Service 8101fe
Packit Service 8101fe
    /* Whether the device was hot-plugged. */
Packit Service 8101fe
    gboolean hotplugged;
Packit Service 8101fe
Packit Service 8101fe
    /* Whether the device is inhibited. */
Packit Service 8101fe
    gboolean inhibited;
Packit Service 8101fe
Packit Service 8101fe
    /* Virtual ports */
Packit Service 8101fe
    gchar **virtual_ports;
Packit Service 8101fe
};
Packit Service 8101fe
Packit Service 8101fe
/*****************************************************************************/
Packit Service 8101fe
Packit Service 8101fe
static MMPortProbe *
Packit Service 8101fe
device_find_probe_with_device (MMDevice       *self,
Packit Service 8101fe
                               MMKernelDevice *kernel_port,
Packit Service 8101fe
                               gboolean        lookup_ignored)
Packit Service 8101fe
{
Packit Service 8101fe
    GList *l;
Packit Service 8101fe
Packit Service 8101fe
    for (l = self->priv->port_probes; l; l = g_list_next (l)) {
Packit Service 8101fe
        MMPortProbe *probe = MM_PORT_PROBE (l->data);
Packit Service 8101fe
Packit Service 8101fe
        if (mm_kernel_device_cmp (mm_port_probe_peek_port (probe), kernel_port))
Packit Service 8101fe
            return probe;
Packit Service 8101fe
    }
Packit Service 8101fe
Packit Service 8101fe
    if (!lookup_ignored)
Packit Service 8101fe
        return NULL;
Packit Service 8101fe
Packit Service 8101fe
    for (l = self->priv->ignored_port_probes; l; l = g_list_next (l)) {
Packit Service 8101fe
        MMPortProbe *probe = MM_PORT_PROBE (l->data);
Packit Service 8101fe
Packit Service 8101fe
        if (mm_kernel_device_cmp (mm_port_probe_peek_port (probe), kernel_port))
Packit Service 8101fe
            return probe;
Packit Service 8101fe
    }
Packit Service 8101fe
Packit Service 8101fe
    return NULL;
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
gboolean
Packit Service 8101fe
mm_device_owns_port (MMDevice       *self,
Packit Service 8101fe
                     MMKernelDevice *kernel_port)
Packit Service 8101fe
{
Packit Service 8101fe
    return !!device_find_probe_with_device (self, kernel_port, TRUE);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
static void
Packit Service 8101fe
add_port_driver (MMDevice       *self,
Packit Service 8101fe
                 MMKernelDevice *kernel_port)
Packit Service 8101fe
{
Packit Service 8101fe
    const gchar *driver;
Packit Service 8101fe
    guint n_items;
Packit Service 8101fe
    guint i;
Packit Service 8101fe
Packit Service 8101fe
    driver = mm_kernel_device_get_driver (kernel_port);
Packit Service 8101fe
    if (!driver)
Packit Service 8101fe
        return;
Packit Service 8101fe
Packit Service 8101fe
    n_items = (self->priv->drivers ? g_strv_length (self->priv->drivers) : 0);
Packit Service 8101fe
    if (n_items > 0) {
Packit Service 8101fe
        /* Add driver to our list of drivers, if not already there */
Packit Service 8101fe
        for (i = 0; self->priv->drivers[i]; i++) {
Packit Service 8101fe
            if (g_str_equal (self->priv->drivers[i], driver)) {
Packit Service 8101fe
                driver = NULL;
Packit Service 8101fe
                break;
Packit Service 8101fe
            }
Packit Service 8101fe
        }
Packit Service 8101fe
    }
Packit Service 8101fe
Packit Service 8101fe
    if (!driver)
Packit Service 8101fe
        return;
Packit Service 8101fe
Packit Service 8101fe
    self->priv->drivers = g_realloc (self->priv->drivers, (n_items + 2) * sizeof (gchar *));
Packit Service 8101fe
    self->priv->drivers[n_items] = g_strdup (driver);
Packit Service 8101fe
    self->priv->drivers[n_items + 1] = NULL;
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
void
Packit Service 8101fe
mm_device_grab_port (MMDevice       *self,
Packit Service 8101fe
                     MMKernelDevice *kernel_port)
Packit Service 8101fe
{
Packit Service 8101fe
    MMPortProbe *probe;
Packit Service 8101fe
Packit Service 8101fe
    if (mm_device_owns_port (self, kernel_port))
Packit Service 8101fe
        return;
Packit Service 8101fe
Packit Service 8101fe
    /* Get the vendor/product IDs out of the first one that gives us
Packit Service 8101fe
     * some valid value (it seems we may get NULL reported for VID in QMI
Packit Service 8101fe
     * ports, e.g. Huawei E367) */
Packit Service 8101fe
    if (!self->priv->vendor && !self->priv->product) {
Packit Service 8101fe
        self->priv->vendor  = mm_kernel_device_get_physdev_vid (kernel_port);
Packit Service 8101fe
        self->priv->product = mm_kernel_device_get_physdev_pid (kernel_port);
Packit Service 8101fe
    }
Packit Service 8101fe
Packit Service 8101fe
    /* Add new port driver */
Packit Service 8101fe
    add_port_driver (self, kernel_port);
Packit Service 8101fe
Packit Service 8101fe
    /* Create and store new port probe */
Packit Service 8101fe
    probe = mm_port_probe_new (self, kernel_port);
Packit Service 8101fe
    self->priv->port_probes = g_list_prepend (self->priv->port_probes, probe);
Packit Service 8101fe
Packit Service 8101fe
    /* Notify about the grabbed port */
Packit Service 8101fe
    g_signal_emit (self, signals[SIGNAL_PORT_GRABBED], 0, kernel_port);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
void
Packit Service 8101fe
mm_device_release_port (MMDevice       *self,
Packit Service 8101fe
                        MMKernelDevice *kernel_port)
Packit Service 8101fe
{
Packit Service 8101fe
    MMPortProbe *probe;
Packit Service 8101fe
Packit Service 8101fe
    probe = device_find_probe_with_device (self, kernel_port, TRUE);
Packit Service 8101fe
    if (probe) {
Packit Service 8101fe
        /* Found, remove from lists and destroy probe */
Packit Service 8101fe
        if (g_list_find (self->priv->port_probes, probe))
Packit Service 8101fe
            self->priv->port_probes = g_list_remove (self->priv->port_probes, probe);
Packit Service 8101fe
        else if (g_list_find (self->priv->ignored_port_probes, probe))
Packit Service 8101fe
            self->priv->ignored_port_probes = g_list_remove (self->priv->ignored_port_probes, probe);
Packit Service 8101fe
        else
Packit Service 8101fe
            g_assert_not_reached ();
Packit Service 8101fe
        g_signal_emit (self, signals[SIGNAL_PORT_RELEASED], 0, mm_port_probe_peek_port (probe));
Packit Service 8101fe
        g_object_unref (probe);
Packit Service 8101fe
    }
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
void
Packit Service 8101fe
mm_device_ignore_port  (MMDevice       *self,
Packit Service 8101fe
                        MMKernelDevice *kernel_port)
Packit Service 8101fe
{
Packit Service 8101fe
    MMPortProbe *probe;
Packit Service 8101fe
Packit Service 8101fe
    probe = device_find_probe_with_device (self, kernel_port, FALSE);
Packit Service 8101fe
    if (probe) {
Packit Service 8101fe
        /* Found, remove from list and add to the ignored list */
Packit Service 8101fe
        mm_dbg ("[device %s] fully ignoring port '%s/%s' from now on",
Packit Service 8101fe
                self->priv->uid,
Packit Service 8101fe
                mm_kernel_device_get_subsystem (kernel_port),
Packit Service 8101fe
                mm_kernel_device_get_name (kernel_port));
Packit Service 8101fe
        self->priv->port_probes = g_list_remove (self->priv->port_probes, probe);
Packit Service 8101fe
        self->priv->ignored_port_probes = g_list_prepend (self->priv->ignored_port_probes, probe);
Packit Service 8101fe
    }
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
/*****************************************************************************/
Packit Service 8101fe
Packit Service 8101fe
static void
Packit Service 8101fe
unexport_modem (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    gchar *path;
Packit Service 8101fe
Packit Service 8101fe
    g_assert (MM_IS_BASE_MODEM (self->priv->modem));
Packit Service 8101fe
    g_assert (G_IS_DBUS_OBJECT_MANAGER (self->priv->object_manager));
Packit Service 8101fe
Packit Service 8101fe
    path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (self->priv->modem)));
Packit Service 8101fe
    if (path != NULL) {
Packit Service 8101fe
        g_dbus_object_manager_server_unexport (self->priv->object_manager, path);
Packit Service 8101fe
        g_object_set (self->priv->modem,
Packit Service 8101fe
                      MM_BASE_MODEM_CONNECTION, NULL,
Packit Service 8101fe
                      NULL);
Packit Service 8101fe
        mm_dbg ("[device %s] unexported modem from path '%s'", self->priv->uid, path);
Packit Service 8101fe
        g_free (path);
Packit Service 8101fe
    }
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
/*****************************************************************************/
Packit Service 8101fe
Packit Service 8101fe
static void
Packit Service 8101fe
export_modem (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    GDBusConnection *connection = NULL;
Packit Service 8101fe
    static guint32 id = 0;
Packit Service 8101fe
    gchar *path;
Packit Service 8101fe
Packit Service 8101fe
    g_assert (MM_IS_BASE_MODEM (self->priv->modem));
Packit Service 8101fe
    g_assert (G_IS_DBUS_OBJECT_MANAGER (self->priv->object_manager));
Packit Service 8101fe
Packit Service 8101fe
    /* If modem not yet valid (not fully initialized), don't export it */
Packit Service 8101fe
    if (!mm_base_modem_get_valid (self->priv->modem)) {
Packit Service 8101fe
        mm_dbg ("[device %s] modem not yet fully initialized", self->priv->uid);
Packit Service 8101fe
        return;
Packit Service 8101fe
    }
Packit Service 8101fe
Packit Service 8101fe
    /* Don't export already exported modems */
Packit Service 8101fe
    g_object_get (self->priv->modem,
Packit Service 8101fe
                  "g-object-path", &path,
Packit Service 8101fe
                  NULL);
Packit Service 8101fe
    if (path) {
Packit Service 8101fe
        g_free (path);
Packit Service 8101fe
        mm_dbg ("[device %s] modem already exported", self->priv->uid);
Packit Service 8101fe
        return;
Packit Service 8101fe
    }
Packit Service 8101fe
Packit Service 8101fe
    /* No outstanding port tasks, so if the modem is valid we can export it */
Packit Service 8101fe
Packit Service 8101fe
    path = g_strdup_printf (MM_DBUS_MODEM_PREFIX "/%d", id++);
Packit Service 8101fe
    g_object_get (self->priv->object_manager,
Packit Service 8101fe
                  "connection", &connection,
Packit Service 8101fe
                  NULL);
Packit Service 8101fe
    g_object_set (self->priv->modem,
Packit Service 8101fe
                  "g-object-path", path,
Packit Service 8101fe
                  MM_BASE_MODEM_CONNECTION, connection,
Packit Service 8101fe
                  NULL);
Packit Service 8101fe
    g_object_unref (connection);
Packit Service 8101fe
Packit Service 8101fe
    g_dbus_object_manager_server_export (self->priv->object_manager,
Packit Service 8101fe
                                         G_DBUS_OBJECT_SKELETON (self->priv->modem));
Packit Service 8101fe
Packit Service 8101fe
    mm_dbg ("[device %s] exported modem at path '%s'", self->priv->uid, path);
Packit Service 8101fe
    mm_dbg ("[device %s]    plugin:  %s", self->priv->uid, mm_base_modem_get_plugin (self->priv->modem));
Packit Service 8101fe
    mm_dbg ("[device %s]    vid:pid: 0x%04X:0x%04X",
Packit Service 8101fe
            self->priv->uid,
Packit Service 8101fe
            (mm_base_modem_get_vendor_id (self->priv->modem) & 0xFFFF),
Packit Service 8101fe
            (mm_base_modem_get_product_id (self->priv->modem) & 0xFFFF));
Packit Service 8101fe
    if (self->priv->virtual)
Packit Service 8101fe
        mm_dbg ("[device %s]    virtual", self->priv->uid);
Packit Service 8101fe
Packit Service 8101fe
    g_free (path);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
/*****************************************************************************/
Packit Service 8101fe
Packit Service 8101fe
static void
Packit Service 8101fe
clear_modem (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    if (self->priv->modem_valid_id) {
Packit Service 8101fe
        g_signal_handler_disconnect (self->priv->modem, self->priv->modem_valid_id);
Packit Service 8101fe
        self->priv->modem_valid_id = 0;
Packit Service 8101fe
    }
Packit Service 8101fe
Packit Service 8101fe
    if (self->priv->modem) {
Packit Service 8101fe
        /* Run dispose before unref-ing, in order to cleanup the SIM object,
Packit Service 8101fe
         * if any (which also holds a reference to the modem object) */
Packit Service 8101fe
        g_object_run_dispose (G_OBJECT (self->priv->modem));
Packit Service 8101fe
        g_clear_object (&(self->priv->modem));
Packit Service 8101fe
    }
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
void
Packit Service 8101fe
mm_device_remove_modem (MMDevice  *self)
Packit Service 8101fe
{
Packit Service 8101fe
    if (!self->priv->modem)
Packit Service 8101fe
        return;
Packit Service 8101fe
Packit Service 8101fe
    unexport_modem (self);
Packit Service 8101fe
    clear_modem (self);
Packit Service 8101fe
    g_clear_object (&(self->priv->object_manager));
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
/*****************************************************************************/
Packit Service 8101fe
Packit Service 8101fe
static void
Packit Service 8101fe
modem_valid (MMBaseModem *modem,
Packit Service 8101fe
             GParamSpec  *pspec,
Packit Service 8101fe
             MMDevice    *self)
Packit Service 8101fe
{
Packit Service 8101fe
    if (!mm_base_modem_get_valid (modem)) {
Packit Service 8101fe
        GDBusObjectManagerServer *object_manager;
Packit Service 8101fe
Packit Service 8101fe
        object_manager = g_object_ref (self->priv->object_manager);
Packit Service 8101fe
Packit Service 8101fe
        /* Modem no longer valid */
Packit Service 8101fe
        mm_device_remove_modem (self);
Packit Service 8101fe
Packit Service 8101fe
        if (mm_base_modem_get_reprobe (modem)) {
Packit Service 8101fe
            GError *error = NULL;
Packit Service 8101fe
Packit Service 8101fe
            if (!mm_device_create_modem (self, object_manager, &error)) {
Packit Service 8101fe
                mm_warn ("Could not recreate modem for device '%s': %s",
Packit Service 8101fe
                         self->priv->uid,
Packit Service 8101fe
                         error ? error->message : "unknown");
Packit Service 8101fe
                g_error_free (error);
Packit Service 8101fe
            } else {
Packit Service 8101fe
                mm_dbg ("Modem recreated for device '%s'", self->priv->uid);
Packit Service 8101fe
            }
Packit Service 8101fe
        }
Packit Service 8101fe
Packit Service 8101fe
        g_object_unref (object_manager);
Packit Service 8101fe
    } else {
Packit Service 8101fe
        /* Modem now valid, export it, but only if we really have it around.
Packit Service 8101fe
         * It may happen that the initialization sequence fails because the
Packit Service 8101fe
         * modem gets disconnected, and in that case we don't really need
Packit Service 8101fe
         * to export it */
Packit Service 8101fe
        if (self->priv->modem)
Packit Service 8101fe
            export_modem (self);
Packit Service 8101fe
        else
Packit Service 8101fe
            mm_dbg ("[device %s] not exporting modem; no longer available", self->priv->uid);
Packit Service 8101fe
    }
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
gboolean
Packit Service 8101fe
mm_device_create_modem (MMDevice                  *self,
Packit Service 8101fe
                        GDBusObjectManagerServer  *object_manager,
Packit Service 8101fe
                        GError                   **error)
Packit Service 8101fe
{
Packit Service 8101fe
    g_assert (self->priv->modem == NULL);
Packit Service 8101fe
    g_assert (self->priv->object_manager == NULL);
Packit Service 8101fe
Packit Service 8101fe
    if (self->priv->inhibited) {
Packit Service 8101fe
        g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
Packit Service 8101fe
                     "Device is inhibited");
Packit Service 8101fe
        return FALSE;
Packit Service 8101fe
    }
Packit Service 8101fe
Packit Service 8101fe
    if (!self->priv->virtual) {
Packit Service 8101fe
        if (!self->priv->port_probes) {
Packit Service 8101fe
            g_set_error (error,
Packit Service 8101fe
                         MM_CORE_ERROR,
Packit Service 8101fe
                         MM_CORE_ERROR_FAILED,
Packit Service 8101fe
                         "Not creating a device without ports");
Packit Service 8101fe
            return FALSE;
Packit Service 8101fe
        }
Packit Service 8101fe
Packit Service 8101fe
        mm_info ("[device %s] creating modem with plugin '%s' and '%u' ports",
Packit Service 8101fe
                 self->priv->uid,
Packit Service 8101fe
                 mm_plugin_get_name (self->priv->plugin),
Packit Service 8101fe
                 g_list_length (self->priv->port_probes));
Packit Service 8101fe
    } else {
Packit Service 8101fe
        if (!self->priv->virtual_ports) {
Packit Service 8101fe
            g_set_error (error,
Packit Service 8101fe
                         MM_CORE_ERROR,
Packit Service 8101fe
                         MM_CORE_ERROR_FAILED,
Packit Service 8101fe
                         "Not creating a virtual device without ports");
Packit Service 8101fe
            return FALSE;
Packit Service 8101fe
        }
Packit Service 8101fe
Packit Service 8101fe
        mm_info ("[device %s] creating virtual modem with plugin '%s' and '%u' ports",
Packit Service 8101fe
                 self->priv->uid,
Packit Service 8101fe
                 mm_plugin_get_name (self->priv->plugin),
Packit Service 8101fe
                 g_strv_length (self->priv->virtual_ports));
Packit Service 8101fe
    }
Packit Service 8101fe
Packit Service 8101fe
    self->priv->modem = mm_plugin_create_modem (self->priv->plugin, self, error);
Packit Service 8101fe
    if (self->priv->modem) {
Packit Service 8101fe
        /* Keep the object manager */
Packit Service 8101fe
        self->priv->object_manager = g_object_ref (object_manager);
Packit Service 8101fe
Packit Service 8101fe
        /* We want to get notified when the modem becomes valid/invalid */
Packit Service 8101fe
        self->priv->modem_valid_id = g_signal_connect (self->priv->modem,
Packit Service 8101fe
                                                       "notify::" MM_BASE_MODEM_VALID,
Packit Service 8101fe
                                                       G_CALLBACK (modem_valid),
Packit Service 8101fe
                                                       self);
Packit Service 8101fe
    }
Packit Service 8101fe
Packit Service 8101fe
    return !!self->priv->modem;
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
/*****************************************************************************/
Packit Service 8101fe
Packit Service 8101fe
const gchar *
Packit Service 8101fe
mm_device_get_uid (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    return self->priv->uid;
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
const gchar **
Packit Service 8101fe
mm_device_get_drivers (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    return (const gchar **)self->priv->drivers;
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
guint16
Packit Service 8101fe
mm_device_get_vendor (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    return self->priv->vendor;
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
guint16
Packit Service 8101fe
mm_device_get_product (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    return self->priv->product;
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
void
Packit Service 8101fe
mm_device_set_plugin (MMDevice *self,
Packit Service 8101fe
                      GObject  *plugin)
Packit Service 8101fe
{
Packit Service 8101fe
    g_object_set (self,
Packit Service 8101fe
                  MM_DEVICE_PLUGIN, plugin,
Packit Service 8101fe
                  NULL);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
GObject *
Packit Service 8101fe
mm_device_peek_plugin (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    return (self->priv->plugin ?
Packit Service 8101fe
            G_OBJECT (self->priv->plugin) :
Packit Service 8101fe
            NULL);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
GObject *
Packit Service 8101fe
mm_device_get_plugin (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    return (self->priv->plugin ?
Packit Service 8101fe
            g_object_ref (self->priv->plugin) :
Packit Service 8101fe
            NULL);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
MMBaseModem *
Packit Service 8101fe
mm_device_peek_modem (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    return (self->priv->modem ?
Packit Service 8101fe
            MM_BASE_MODEM (self->priv->modem) :
Packit Service 8101fe
            NULL);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
MMBaseModem *
Packit Service 8101fe
mm_device_get_modem (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    return (self->priv->modem ?
Packit Service 8101fe
            MM_BASE_MODEM (g_object_ref (self->priv->modem)) :
Packit Service 8101fe
            NULL);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
GObject *
Packit Service 8101fe
mm_device_peek_port_probe (MMDevice       *self,
Packit Service 8101fe
                           MMKernelDevice *kernel_port)
Packit Service 8101fe
{
Packit Service 8101fe
    MMPortProbe *probe;
Packit Service 8101fe
Packit Service 8101fe
    probe = device_find_probe_with_device (self, kernel_port, FALSE);
Packit Service 8101fe
    return (probe ? G_OBJECT (probe) : NULL);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
GObject *
Packit Service 8101fe
mm_device_get_port_probe (MMDevice       *self,
Packit Service 8101fe
                          MMKernelDevice *kernel_port)
Packit Service 8101fe
{
Packit Service 8101fe
    MMPortProbe *probe;
Packit Service 8101fe
Packit Service 8101fe
    probe = device_find_probe_with_device (self, kernel_port, FALSE);
Packit Service 8101fe
    return (probe ? g_object_ref (probe) : NULL);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
GList *
Packit Service 8101fe
mm_device_peek_port_probe_list (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    return self->priv->port_probes;
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
GList *
Packit Service 8101fe
mm_device_get_port_probe_list (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    return g_list_copy_deep (self->priv->port_probes,
Packit Service 8101fe
                             (GCopyFunc)g_object_ref,
Packit Service 8101fe
                             NULL);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
gboolean
Packit Service 8101fe
mm_device_get_hotplugged (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    return self->priv->hotplugged;
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
gboolean
Packit Service 8101fe
mm_device_get_inhibited (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    return self->priv->inhibited;
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
/*****************************************************************************/
Packit Service 8101fe
Packit Service 8101fe
gboolean
Packit Service 8101fe
mm_device_inhibit_finish (MMDevice      *self,
Packit Service 8101fe
                          GAsyncResult  *res,
Packit Service 8101fe
                          GError       **error)
Packit Service 8101fe
{
Packit Service 8101fe
    return g_task_propagate_boolean (G_TASK (res), error);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
static void
Packit Service 8101fe
inhibit_disable_ready (MMBaseModem  *modem,
Packit Service 8101fe
                       GAsyncResult *res,
Packit Service 8101fe
                       GTask        *task)
Packit Service 8101fe
{
Packit Service 8101fe
    MMDevice *self;
Packit Service 8101fe
    GError   *error = NULL;
Packit Service 8101fe
Packit Service 8101fe
    self = g_task_get_source_object (task);
Packit Service 8101fe
Packit Service 8101fe
    if (!mm_base_modem_disable_finish (modem, res, &error))
Packit Service 8101fe
        g_task_return_error (task, error);
Packit Service 8101fe
    else {
Packit Service 8101fe
        g_cancellable_cancel (mm_base_modem_peek_cancellable (modem));
Packit Service 8101fe
        mm_device_remove_modem (self);
Packit Service 8101fe
        g_task_return_boolean (task, TRUE);
Packit Service 8101fe
    }
Packit Service 8101fe
    g_object_unref (task);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
void
Packit Service 8101fe
mm_device_inhibit (MMDevice            *self,
Packit Service 8101fe
                   GAsyncReadyCallback  callback,
Packit Service 8101fe
                   gpointer             user_data)
Packit Service 8101fe
{
Packit Service 8101fe
    GTask *task;
Packit Service 8101fe
Packit Service 8101fe
    task = g_task_new (self, NULL, callback, user_data);
Packit Service 8101fe
Packit Service 8101fe
    /* We want to allow inhibiting only devices that are currently
Packit Service 8101fe
     * exported in the bus, because otherwise we may be inhibiting
Packit Service 8101fe
     * in the middle of port probing and that may lead to some ports
Packit Service 8101fe
     * tracked inside the device object during inhibition and some
Packit Service 8101fe
     * other ports tracked in the base manager. So, if the device
Packit Service 8101fe
     * does not have a valid modem created and exposed, do not allow
Packit Service 8101fe
     * the inhibition. */
Packit Service 8101fe
    if (!self->priv->modem || !g_dbus_object_get_object_path (G_DBUS_OBJECT (self->priv->modem))) {
Packit Service 8101fe
        g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE,
Packit Service 8101fe
                                 "Modem not exported in the bus");
Packit Service 8101fe
        g_object_unref (task);
Packit Service 8101fe
        return;
Packit Service 8101fe
    }
Packit Service 8101fe
Packit Service 8101fe
    /* Flag as inhibited right away */
Packit Service 8101fe
    g_assert (!self->priv->inhibited);
Packit Service 8101fe
    self->priv->inhibited = TRUE;
Packit Service 8101fe
Packit Service 8101fe
    /* Make sure modem is disabled while inhibited */
Packit Service 8101fe
    mm_base_modem_disable (self->priv->modem,
Packit Service 8101fe
                           (GAsyncReadyCallback)inhibit_disable_ready,
Packit Service 8101fe
                           task);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
gboolean
Packit Service 8101fe
mm_device_uninhibit (MMDevice                  *self,
Packit Service 8101fe
                     GDBusObjectManagerServer  *object_manager,
Packit Service 8101fe
                     GError                   **error)
Packit Service 8101fe
{
Packit Service 8101fe
    g_assert (self->priv->inhibited);
Packit Service 8101fe
    self->priv->inhibited = FALSE;
Packit Service 8101fe
    return mm_device_create_modem (self, object_manager, error);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
/*****************************************************************************/
Packit Service 8101fe
Packit Service 8101fe
void
Packit Service 8101fe
mm_device_virtual_grab_ports (MMDevice *self,
Packit Service 8101fe
                              const gchar **ports)
Packit Service 8101fe
{
Packit Service 8101fe
    g_return_if_fail (ports != NULL);
Packit Service 8101fe
    g_return_if_fail (self->priv->virtual);
Packit Service 8101fe
Packit Service 8101fe
    /* Setup drivers array */
Packit Service 8101fe
    self->priv->drivers = g_malloc (2 * sizeof (gchar *));
Packit Service 8101fe
    self->priv->drivers[0] = g_strdup ("virtual");
Packit Service 8101fe
    self->priv->drivers[1] = NULL;
Packit Service 8101fe
Packit Service 8101fe
    /* Keep virtual port names */
Packit Service 8101fe
    self->priv->virtual_ports = g_strdupv ((gchar **)ports);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
const gchar **
Packit Service 8101fe
mm_device_virtual_peek_ports (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    g_return_val_if_fail (self->priv->virtual, NULL);
Packit Service 8101fe
Packit Service 8101fe
    return (const gchar **)self->priv->virtual_ports;
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
gboolean
Packit Service 8101fe
mm_device_is_virtual (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    return self->priv->virtual;
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
/*****************************************************************************/
Packit Service 8101fe
Packit Service 8101fe
MMDevice *
Packit Service 8101fe
mm_device_new (const gchar *uid,
Packit Service 8101fe
               gboolean     hotplugged,
Packit Service 8101fe
               gboolean     virtual)
Packit Service 8101fe
{
Packit Service 8101fe
    g_return_val_if_fail (uid != NULL, NULL);
Packit Service 8101fe
Packit Service 8101fe
    return MM_DEVICE (g_object_new (MM_TYPE_DEVICE,
Packit Service 8101fe
                                    MM_DEVICE_UID,        uid,
Packit Service 8101fe
                                    MM_DEVICE_HOTPLUGGED, hotplugged,
Packit Service 8101fe
                                    MM_DEVICE_VIRTUAL,    virtual,
Packit Service 8101fe
                                    NULL));
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
static void
Packit Service 8101fe
mm_device_init (MMDevice *self)
Packit Service 8101fe
{
Packit Service 8101fe
    /* Initialize private data */
Packit Service 8101fe
    self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_DEVICE, MMDevicePrivate);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
static void
Packit Service 8101fe
set_property (GObject *object,
Packit Service 8101fe
              guint prop_id,
Packit Service 8101fe
              const GValue *value,
Packit Service 8101fe
              GParamSpec *pspec)
Packit Service 8101fe
{
Packit Service 8101fe
    MMDevice *self = MM_DEVICE (object);
Packit Service 8101fe
Packit Service 8101fe
    switch (prop_id) {
Packit Service 8101fe
    case PROP_UID:
Packit Service 8101fe
        /* construct only */
Packit Service 8101fe
        self->priv->uid = g_value_dup_string (value);
Packit Service 8101fe
        break;
Packit Service 8101fe
    case PROP_PLUGIN:
Packit Service 8101fe
        g_clear_object (&(self->priv->plugin));
Packit Service 8101fe
        self->priv->plugin = g_value_dup_object (value);
Packit Service 8101fe
        break;
Packit Service 8101fe
    case PROP_MODEM:
Packit Service 8101fe
        clear_modem (self);
Packit Service 8101fe
        self->priv->modem = g_value_dup_object (value);
Packit Service 8101fe
        break;
Packit Service 8101fe
    case PROP_HOTPLUGGED:
Packit Service 8101fe
        self->priv->hotplugged = g_value_get_boolean (value);
Packit Service 8101fe
        break;
Packit Service 8101fe
    case PROP_VIRTUAL:
Packit Service 8101fe
        self->priv->virtual = g_value_get_boolean (value);
Packit Service 8101fe
        break;
Packit Service 8101fe
    case PROP_INHIBITED:
Packit Service 8101fe
        self->priv->inhibited = g_value_get_boolean (value);
Packit Service 8101fe
        break;
Packit Service 8101fe
    default:
Packit Service 8101fe
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit Service 8101fe
        break;
Packit Service 8101fe
    }
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
static void
Packit Service 8101fe
get_property (GObject *object,
Packit Service 8101fe
              guint prop_id,
Packit Service 8101fe
              GValue *value,
Packit Service 8101fe
              GParamSpec *pspec)
Packit Service 8101fe
{
Packit Service 8101fe
    MMDevice *self = MM_DEVICE (object);
Packit Service 8101fe
Packit Service 8101fe
    switch (prop_id) {
Packit Service 8101fe
    case PROP_UID:
Packit Service 8101fe
        g_value_set_string (value, self->priv->uid);
Packit Service 8101fe
        break;
Packit Service 8101fe
    case PROP_PLUGIN:
Packit Service 8101fe
        g_value_set_object (value, self->priv->plugin);
Packit Service 8101fe
        break;
Packit Service 8101fe
    case PROP_MODEM:
Packit Service 8101fe
        g_value_set_object (value, self->priv->modem);
Packit Service 8101fe
        break;
Packit Service 8101fe
    case PROP_HOTPLUGGED:
Packit Service 8101fe
        g_value_set_boolean (value, self->priv->hotplugged);
Packit Service 8101fe
        break;
Packit Service 8101fe
    case PROP_VIRTUAL:
Packit Service 8101fe
        g_value_set_boolean (value, self->priv->virtual);
Packit Service 8101fe
        break;
Packit Service 8101fe
    case PROP_INHIBITED:
Packit Service 8101fe
        g_value_set_boolean (value, self->priv->inhibited);
Packit Service 8101fe
        break;
Packit Service 8101fe
    default:
Packit Service 8101fe
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit Service 8101fe
        break;
Packit Service 8101fe
    }
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
static void
Packit Service 8101fe
dispose (GObject *object)
Packit Service 8101fe
{
Packit Service 8101fe
    MMDevice *self = MM_DEVICE (object);
Packit Service 8101fe
Packit Service 8101fe
    g_clear_object (&(self->priv->plugin));
Packit Service 8101fe
    g_list_free_full (self->priv->port_probes, g_object_unref);
Packit Service 8101fe
    self->priv->port_probes = NULL;
Packit Service 8101fe
    g_list_free_full (self->priv->ignored_port_probes, g_object_unref);
Packit Service 8101fe
    self->priv->ignored_port_probes = NULL;
Packit Service 8101fe
Packit Service 8101fe
    clear_modem (self);
Packit Service 8101fe
Packit Service 8101fe
    G_OBJECT_CLASS (mm_device_parent_class)->dispose (object);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
static void
Packit Service 8101fe
finalize (GObject *object)
Packit Service 8101fe
{
Packit Service 8101fe
    MMDevice *self = MM_DEVICE (object);
Packit Service 8101fe
Packit Service 8101fe
    g_free (self->priv->uid);
Packit Service 8101fe
    g_strfreev (self->priv->drivers);
Packit Service 8101fe
    g_strfreev (self->priv->virtual_ports);
Packit Service 8101fe
Packit Service 8101fe
    G_OBJECT_CLASS (mm_device_parent_class)->finalize (object);
Packit Service 8101fe
}
Packit Service 8101fe
Packit Service 8101fe
static void
Packit Service 8101fe
mm_device_class_init (MMDeviceClass *klass)
Packit Service 8101fe
{
Packit Service 8101fe
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit Service 8101fe
Packit Service 8101fe
    g_type_class_add_private (object_class, sizeof (MMDevicePrivate));
Packit Service 8101fe
Packit Service 8101fe
    /* Virtual methods */
Packit Service 8101fe
    object_class->get_property = get_property;
Packit Service 8101fe
    object_class->set_property = set_property;
Packit Service 8101fe
    object_class->finalize     = finalize;
Packit Service 8101fe
    object_class->dispose      = dispose;
Packit Service 8101fe
Packit Service 8101fe
    properties[PROP_UID] =
Packit Service 8101fe
        g_param_spec_string (MM_DEVICE_UID,
Packit Service 8101fe
                             "Unique ID",
Packit Service 8101fe
                             "Unique device id, e.g. the physical device sysfs path",
Packit Service 8101fe
                             NULL,
Packit Service 8101fe
                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
Packit Service 8101fe
    g_object_class_install_property (object_class, PROP_UID, properties[PROP_UID]);
Packit Service 8101fe
Packit Service 8101fe
    properties[PROP_PLUGIN] =
Packit Service 8101fe
        g_param_spec_object (MM_DEVICE_PLUGIN,
Packit Service 8101fe
                             "Plugin",
Packit Service 8101fe
                             "Best plugin to manage this device",
Packit Service 8101fe
                             MM_TYPE_PLUGIN,
Packit Service 8101fe
                             G_PARAM_READWRITE);
Packit Service 8101fe
    g_object_class_install_property (object_class, PROP_PLUGIN, properties[PROP_PLUGIN]);
Packit Service 8101fe
Packit Service 8101fe
    properties[PROP_MODEM] =
Packit Service 8101fe
        g_param_spec_object (MM_DEVICE_MODEM,
Packit Service 8101fe
                             "Modem",
Packit Service 8101fe
                             "The modem object",
Packit Service 8101fe
                             MM_TYPE_BASE_MODEM,
Packit Service 8101fe
                             G_PARAM_READWRITE);
Packit Service 8101fe
    g_object_class_install_property (object_class, PROP_MODEM, properties[PROP_MODEM]);
Packit Service 8101fe
Packit Service 8101fe
    properties[PROP_HOTPLUGGED] =
Packit Service 8101fe
        g_param_spec_boolean (MM_DEVICE_HOTPLUGGED,
Packit Service 8101fe
                              "Hotplugged",
Packit Service 8101fe
                              "Whether the modem was hotplugged",
Packit Service 8101fe
                              FALSE,
Packit Service 8101fe
                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
Packit Service 8101fe
    g_object_class_install_property (object_class, PROP_HOTPLUGGED, properties[PROP_HOTPLUGGED]);
Packit Service 8101fe
Packit Service 8101fe
    properties[PROP_VIRTUAL] =
Packit Service 8101fe
        g_param_spec_boolean (MM_DEVICE_VIRTUAL,
Packit Service 8101fe
                              "Virtual",
Packit Service 8101fe
                              "Whether the device is virtual or real",
Packit Service 8101fe
                              FALSE,
Packit Service 8101fe
                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
Packit Service 8101fe
    g_object_class_install_property (object_class, PROP_VIRTUAL, properties[PROP_VIRTUAL]);
Packit Service 8101fe
Packit Service 8101fe
    properties[PROP_INHIBITED] =
Packit Service 8101fe
        g_param_spec_boolean (MM_DEVICE_INHIBITED,
Packit Service 8101fe
                              "Inhibited",
Packit Service 8101fe
                              "Whether the modem is inhibited",
Packit Service 8101fe
                              FALSE,
Packit Service 8101fe
                              G_PARAM_READWRITE);
Packit Service 8101fe
    g_object_class_install_property (object_class, PROP_INHIBITED, properties[PROP_INHIBITED]);
Packit Service 8101fe
Packit Service 8101fe
    signals[SIGNAL_PORT_GRABBED] =
Packit Service 8101fe
        g_signal_new (MM_DEVICE_PORT_GRABBED,
Packit Service 8101fe
                      G_OBJECT_CLASS_TYPE (object_class),
Packit Service 8101fe
                      G_SIGNAL_RUN_FIRST,
Packit Service 8101fe
                      G_STRUCT_OFFSET (MMDeviceClass, port_grabbed),
Packit Service 8101fe
                      NULL, NULL,
Packit Service 8101fe
                      g_cclosure_marshal_generic,
Packit Service 8101fe
                      G_TYPE_NONE, 1, MM_TYPE_KERNEL_DEVICE);
Packit Service 8101fe
Packit Service 8101fe
    signals[SIGNAL_PORT_RELEASED] =
Packit Service 8101fe
        g_signal_new (MM_DEVICE_PORT_RELEASED,
Packit Service 8101fe
                      G_OBJECT_CLASS_TYPE (object_class),
Packit Service 8101fe
                      G_SIGNAL_RUN_FIRST,
Packit Service 8101fe
                      G_STRUCT_OFFSET (MMDeviceClass, port_released),
Packit Service 8101fe
                      NULL, NULL,
Packit Service 8101fe
                      g_cclosure_marshal_generic,
Packit Service 8101fe
                      G_TYPE_NONE, 1, MM_TYPE_KERNEL_DEVICE);
Packit Service 8101fe
}