diff options
-rw-r--r-- | include/ModemManager-errors.h | 2 | ||||
-rw-r--r-- | plugins/Makefile.am | 2 | ||||
-rw-r--r-- | plugins/anydata/mm-plugin-anydata.c | 60 | ||||
-rw-r--r-- | plugins/cinterion/mm-plugin-cinterion.c | 61 | ||||
-rw-r--r-- | plugins/generic/mm-plugin-generic.c | 80 | ||||
-rw-r--r-- | plugins/gobi/mm-plugin-gobi.c | 63 | ||||
-rw-r--r-- | plugins/iridium/mm-plugin-iridium.c | 65 | ||||
-rw-r--r-- | plugins/linktop/mm-plugin-linktop.c | 64 | ||||
-rw-r--r-- | plugins/motorola/mm-plugin-motorola.c | 63 | ||||
-rw-r--r-- | plugins/nokia/mm-plugin-nokia.c | 73 | ||||
-rw-r--r-- | plugins/novatel/mm-plugin-novatel.c | 58 | ||||
-rw-r--r-- | plugins/option/mm-plugin-hso.c | 57 | ||||
-rw-r--r-- | plugins/option/mm-plugin-option.c | 63 | ||||
-rw-r--r-- | plugins/simtech/mm-plugin-simtech.c | 61 | ||||
-rw-r--r-- | plugins/wavecom/mm-plugin-wavecom.c | 62 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/mm-device.c | 413 | ||||
-rw-r--r-- | src/mm-device.h | 74 | ||||
-rw-r--r-- | src/mm-manager.c | 486 | ||||
-rw-r--r-- | src/mm-plugin-base.c | 98 | ||||
-rw-r--r-- | src/mm-plugin-base.h | 17 | ||||
-rw-r--r-- | src/mm-plugin.c | 15 | ||||
-rw-r--r-- | src/mm-plugin.h | 23 |
23 files changed, 1095 insertions, 867 deletions
diff --git a/include/ModemManager-errors.h b/include/ModemManager-errors.h index d0779683..36f882cf 100644 --- a/include/ModemManager-errors.h +++ b/include/ModemManager-errors.h @@ -49,6 +49,7 @@ * @MM_CORE_ERROR_TOO_MANY: Too many items. * @MM_CORE_ERROR_NOT_FOUND: Item not found. * @MM_CORE_ERROR_RETRY: Operation cannot yet be performed, retry later. + * @MM_CORE_ERROR_EXISTS: Item already exists. * * Common errors that may be reported by ModemManager. */ @@ -66,6 +67,7 @@ typedef enum { /*< underscore_name=mm_core_error >*/ MM_CORE_ERROR_TOO_MANY = 10, /*< nick=TooMany >*/ MM_CORE_ERROR_NOT_FOUND = 11, /*< nick=NotFound >*/ MM_CORE_ERROR_RETRY = 12, /*< nick=Retry >*/ + MM_CORE_ERROR_EXISTS = 13, /*< nick=Exists >*/ } MMCoreError; /** diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 04678693..5c571671 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -37,9 +37,9 @@ udevrules_DATA = pkglib_LTLIBRARIES = \ libmm-plugin-generic.la \ + libmm-plugin-nokia.la \ libmm-plugin-cinterion.la \ libmm-plugin-iridium.la \ - libmm-plugin-nokia.la \ libmm-plugin-gobi.la \ libmm-plugin-motorola.la \ libmm-plugin-novatel.la \ diff --git a/plugins/anydata/mm-plugin-anydata.c b/plugins/anydata/mm-plugin-anydata.c index 4a8cec4d..9d7304e7 100644 --- a/plugins/anydata/mm-plugin-anydata.c +++ b/plugins/anydata/mm-plugin-anydata.c @@ -32,46 +32,33 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; /*****************************************************************************/ static MMBaseModem * +create_modem (MMPluginBase *plugin, + const gchar *sysfs_path, + const gchar *driver, + guint16 vendor, + guint16 product, + GList *probes, + GError **error) +{ + return MM_BASE_MODEM (mm_broadband_modem_anydata_new (sysfs_path, + driver, + mm_plugin_get_name (MM_PLUGIN (plugin)), + vendor, + product)); +} + +static gboolean grab_port (MMPluginBase *base, - MMBaseModem *existing, + MMBaseModem *modem, MMPortProbe *probe, GError **error) { - MMBaseModem *modem = NULL; - const gchar *name, *subsys; - guint16 vendor = 0, product = 0; - - subsys = mm_port_probe_get_port_subsys (probe); - name = mm_port_probe_get_port_name (probe); - - if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) { - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Could not get modem product ID"); - return NULL; - } - - /* If this is the first port being grabbed, create a new modem object */ - if (!existing) - modem = MM_BASE_MODEM (mm_broadband_modem_anydata_new (mm_port_probe_get_port_physdev (probe), - mm_port_probe_get_port_driver (probe), - mm_plugin_get_name (MM_PLUGIN (base)), - vendor, - product)); - - if (!mm_base_modem_grab_port (existing ? existing : modem, - subsys, - name, - mm_port_probe_get_port_type (probe), - MM_AT_PORT_FLAG_NONE, - error)) { - if (modem) - g_object_unref (modem); - return NULL; - } - - return existing ? existing : modem; + return mm_base_modem_grab_port (modem, + mm_port_probe_get_port_subsys (probe), + mm_port_probe_get_port_name (probe), + mm_port_probe_get_port_type (probe), + MM_AT_PORT_FLAG_NONE, + error); } /*****************************************************************************/ @@ -102,5 +89,6 @@ mm_plugin_anydata_class_init (MMPluginAnydataClass *klass) { MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass); + pb_class->create_modem = create_modem; pb_class->grab_port = grab_port; } diff --git a/plugins/cinterion/mm-plugin-cinterion.c b/plugins/cinterion/mm-plugin-cinterion.c index e712d692..8ecdac3e 100644 --- a/plugins/cinterion/mm-plugin-cinterion.c +++ b/plugins/cinterion/mm-plugin-cinterion.c @@ -17,7 +17,7 @@ * Boston, MA 02111-1307, USA. * * Copyright (C) 2011 Ammonit Measurement GmbH - * Copyright (C) 2011 Google Inc. + * Copyright (C) 2011 - 2012 Google Inc. * Author: Aleksander Morgado <aleksander@lanedo.com> */ @@ -36,14 +36,27 @@ int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; static MMBaseModem * +create_modem (MMPluginBase *plugin, + const gchar *sysfs_path, + const gchar *driver, + guint16 vendor, + guint16 product, + GList *probes, + GError **error) +{ + return MM_BASE_MODEM (mm_broadband_modem_cinterion_new (sysfs_path, + driver, + mm_plugin_get_name (MM_PLUGIN (plugin)), + vendor, + product)); +} + +static gboolean grab_port (MMPluginBase *base, - MMBaseModem *existing, + MMBaseModem *modem, MMPortProbe *probe, GError **error) { - MMBaseModem *modem = NULL; - const gchar *name, *subsys, *driver; - guint16 vendor = 0, product = 0; /* The Cinterion plugin cannot do anything with non-AT ports */ if (!mm_port_probe_is_at (probe)) { @@ -51,38 +64,15 @@ grab_port (MMPluginBase *base, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Ignoring non-AT port"); - return NULL; - } - - subsys = mm_port_probe_get_port_subsys (probe); - name = mm_port_probe_get_port_name (probe); - driver = mm_port_probe_get_port_driver (probe); - - /* Try to get Product IDs from udev. Note that it is not an error - * if we can't get them in our case, as we also support serial - * modems. */ - mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product); - - /* If this is the first port being grabbed, create a new modem object */ - if (!existing) - modem = MM_BASE_MODEM (mm_broadband_modem_cinterion_new (mm_port_probe_get_port_physdev (probe), - driver, - mm_plugin_get_name (MM_PLUGIN (base)), - vendor, - product)); - - if (!mm_base_modem_grab_port (existing ? existing : modem, - subsys, - name, - MM_PORT_TYPE_AT, /* we only allow AT ports here */ - MM_AT_PORT_FLAG_NONE, - error)) { - if (modem) - g_object_unref (modem); - return NULL; + return FALSE; } - return existing ? existing : modem; + return mm_base_modem_grab_port (modem, + mm_port_probe_get_port_subsys (probe), + mm_port_probe_get_port_name (probe), + MM_PORT_TYPE_AT, /* we only allow AT ports here */ + MM_AT_PORT_FLAG_NONE, + error); } /*****************************************************************************/ @@ -114,5 +104,6 @@ mm_plugin_cinterion_class_init (MMPluginCinterionClass *klass) { MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass); + pb_class->create_modem = create_modem; pb_class->grab_port = grab_port; } diff --git a/plugins/generic/mm-plugin-generic.c b/plugins/generic/mm-plugin-generic.c index 02430838..844e7856 100644 --- a/plugins/generic/mm-plugin-generic.c +++ b/plugins/generic/mm-plugin-generic.c @@ -40,19 +40,27 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; /*****************************************************************************/ static MMBaseModem * +create_modem (MMPluginBase *plugin, + const gchar *sysfs_path, + const gchar *driver, + guint16 vendor, + guint16 product, + GList *probes, + GError **error) +{ + return MM_BASE_MODEM (mm_broadband_modem_new (sysfs_path, + driver, + mm_plugin_get_name (MM_PLUGIN (plugin)), + vendor, + product)); +} + +static gboolean grab_port (MMPluginBase *base, - MMBaseModem *existing, + MMBaseModem *modem, MMPortProbe *probe, GError **error) { - GUdevDevice *port; - MMBaseModem *modem = NULL; - const gchar *name, *subsys, *devfile, *driver; - guint16 vendor = 0, product = 0; - - subsys = mm_port_probe_get_port_subsys (probe); - name = mm_port_probe_get_port_name (probe); - /* The generic plugin cannot do anything with non-AT and non-QCDM ports */ if (!mm_port_probe_is_at (probe) && !mm_port_probe_is_qcdm (probe)) { @@ -60,54 +68,15 @@ grab_port (MMPluginBase *base, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Ignoring non-AT/non-QCDM ports"); - return NULL; - } - - driver = mm_port_probe_get_port_driver (probe); - port = mm_port_probe_get_port (probe); - - /* Check device file of the port, we expect one */ - devfile = g_udev_device_get_device_file (port); - if (!devfile) { - if (!driver || !g_str_equal (driver, "bluetooth")) { - g_set_error (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Could not get port's sysfs file."); - return NULL; - } - - mm_warn ("%s: (%s/%s) WARNING: missing udev 'device' file", - mm_plugin_get_name (MM_PLUGIN (base)), - subsys, - name); - } - - /* Vendor and Product IDs are really optional, we'll just warn if they - * cannot get loaded */ - if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) - mm_warn ("Could not get modem vendor/product ID"); - - /* If this is the first port being grabbed, create a new modem object */ - if (!existing) - modem = MM_BASE_MODEM (mm_broadband_modem_new (mm_port_probe_get_port_physdev (probe), - driver, - mm_plugin_get_name (MM_PLUGIN (base)), - vendor, - product)); - - if (!mm_base_modem_grab_port (existing ? existing : modem, - subsys, - name, - mm_port_probe_get_port_type (probe), - MM_AT_PORT_FLAG_NONE, - error)) { - if (modem) - g_object_unref (modem); - return NULL; + return FALSE; } - return existing ? existing : modem; + return mm_base_modem_grab_port (modem, + mm_port_probe_get_port_subsys (probe), + mm_port_probe_get_port_name (probe), + mm_port_probe_get_port_type (probe), + MM_AT_PORT_FLAG_NONE, + error); } /*****************************************************************************/ @@ -136,5 +105,6 @@ mm_plugin_generic_class_init (MMPluginGenericClass *klass) { MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass); + pb_class->create_modem = create_modem; pb_class->grab_port = grab_port; } diff --git a/plugins/gobi/mm-plugin-gobi.c b/plugins/gobi/mm-plugin-gobi.c index 690b5210..cb47d58d 100644 --- a/plugins/gobi/mm-plugin-gobi.c +++ b/plugins/gobi/mm-plugin-gobi.c @@ -30,56 +30,42 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; /*****************************************************************************/ static MMBaseModem * +create_modem (MMPluginBase *plugin, + const gchar *sysfs_path, + const gchar *driver, + guint16 vendor, + guint16 product, + GList *probes, + GError **error) +{ + return MM_BASE_MODEM (mm_broadband_modem_gobi_new (sysfs_path, + driver, + mm_plugin_get_name (MM_PLUGIN (plugin)), + vendor, + product)); +} + +static gboolean grab_port (MMPluginBase *base, - MMBaseModem *existing, + MMBaseModem *modem, MMPortProbe *probe, GError **error) { - MMBaseModem *modem = NULL; - const gchar *name, *subsys, *driver; - guint16 vendor = 0, product = 0; - /* The Gobi plugin only handles AT and QCDM ports (for now) */ if (!mm_port_probe_is_at (probe) && !mm_port_probe_is_qcdm (probe)) { g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Ignoring non-AT/non-QCDM port"); - return NULL; - } - - subsys = mm_port_probe_get_port_subsys (probe); - name = mm_port_probe_get_port_name (probe); - driver = mm_port_probe_get_port_driver (probe); - - if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) { - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Could not get modem product ID"); - return NULL; - } - - /* If this is the first port being grabbed, create a new modem object */ - if (!existing) - modem = MM_BASE_MODEM (mm_broadband_modem_gobi_new (mm_port_probe_get_port_physdev (probe), - driver, - mm_plugin_get_name (MM_PLUGIN (base)), - vendor, - product)); - - if (!mm_base_modem_grab_port (existing ? existing : modem, - subsys, - name, - mm_port_probe_get_port_type (probe), - MM_AT_PORT_FLAG_NONE, - error)) { - if (modem) - g_object_unref (modem); - return NULL; + return FALSE; } - return existing ? existing : modem; + return mm_base_modem_grab_port (modem, + mm_port_probe_get_port_subsys (probe), + mm_port_probe_get_port_name (probe), + mm_port_probe_get_port_type (probe), + MM_AT_PORT_FLAG_NONE, + error); } /*****************************************************************************/ @@ -110,5 +96,6 @@ mm_plugin_gobi_class_init (MMPluginGobiClass *klass) { MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass); + pb_class->create_modem = create_modem; pb_class->grab_port = grab_port; } diff --git a/plugins/iridium/mm-plugin-iridium.c b/plugins/iridium/mm-plugin-iridium.c index 1bfaf522..eb881876 100644 --- a/plugins/iridium/mm-plugin-iridium.c +++ b/plugins/iridium/mm-plugin-iridium.c @@ -16,11 +16,7 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * -<<<<<<< HEAD - * Copyright (C) 2011 Ammonit Measurement GmbH -======= * Copyright (C) 2011 - 2012 Ammonit Measurement GmbH ->>>>>>> 4ce461e... iridium: start porting the Iridium plugin to the '06-api' codebase * Author: Aleksander Morgado <aleksander@lanedo.com> */ @@ -40,54 +36,42 @@ int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; static MMBaseModem * +create_modem (MMPluginBase *plugin, + const gchar *sysfs_path, + const gchar *driver, + guint16 vendor, + guint16 product, + GList *probes, + GError **error) +{ + return MM_BASE_MODEM (mm_broadband_modem_iridium_new (sysfs_path, + driver, + mm_plugin_get_name (MM_PLUGIN (plugin)), + vendor, + product)); +} + +static gboolean grab_port (MMPluginBase *base, - MMBaseModem *existing, + MMBaseModem *modem, MMPortProbe *probe, GError **error) { - MMBaseModem *modem = NULL; - const gchar *name, *subsys, *driver; - guint16 vendor = 0, product = 0; - /* The Iridium plugin cannot do anything with non-AT ports */ if (!mm_port_probe_is_at (probe)) { g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Ignoring non-AT port"); - return NULL; - } - - subsys = mm_port_probe_get_port_subsys (probe); - name = mm_port_probe_get_port_name (probe); - driver = mm_port_probe_get_port_driver (probe); - - /* Try to get Product IDs from udev. Note that it is not an error - * if we can't get them in our case, as we also support serial - * modems. */ - mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product); - - /* If this is the first port being grabbed, create a new modem object */ - if (!existing) - modem = MM_BASE_MODEM (mm_broadband_modem_iridium_new ( - mm_port_probe_get_port_physdev (probe), - driver, - mm_plugin_get_name (MM_PLUGIN (base)), - vendor, - product)); - - if (!mm_base_modem_grab_port (existing ? existing : modem, - subsys, - name, - MM_PORT_TYPE_AT, /* we only allow AT ports here */ - MM_AT_PORT_FLAG_NONE, - error)) { - if (modem) - g_object_unref (modem); - return NULL; + return FALSE; } - return existing ? existing : modem; + return mm_base_modem_grab_port (modem, + mm_port_probe_get_port_subsys (probe), + mm_port_probe_get_port_name (probe), + MM_PORT_TYPE_AT, /* we only allow AT ports here */ + MM_AT_PORT_FLAG_NONE, + error); } /*****************************************************************************/ @@ -123,5 +107,6 @@ mm_plugin_iridium_class_init (MMPluginIridiumClass *klass) { MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass); + pb_class->create_modem = create_modem; pb_class->grab_port = grab_port; } diff --git a/plugins/linktop/mm-plugin-linktop.c b/plugins/linktop/mm-plugin-linktop.c index 69a8e881..e05a2697 100644 --- a/plugins/linktop/mm-plugin-linktop.c +++ b/plugins/linktop/mm-plugin-linktop.c @@ -30,15 +30,29 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; /*****************************************************************************/ static MMBaseModem * +create_modem (MMPluginBase *plugin, + const gchar *sysfs_path, + const gchar *driver, + guint16 vendor, + guint16 product, + GList *probes, + GError **error) +{ + return MM_BASE_MODEM (mm_broadband_modem_linktop_new (sysfs_path, + driver, + mm_plugin_get_name (MM_PLUGIN (plugin)), + vendor, + product)); +} + +static gboolean grab_port (MMPluginBase *base, - MMBaseModem *existing, + MMBaseModem *modem, MMPortProbe *probe, GError **error) { - MMBaseModem *modem = NULL; GUdevDevice *port; - const gchar *name, *subsys, *devfile; - guint16 vendor = 0, product = 0; + const gchar *devfile; /* The Linktop plugin cannot do anything with non-AT ports */ if (!mm_port_probe_is_at (probe)) { @@ -46,7 +60,7 @@ grab_port (MMPluginBase *base, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Ignoring non-AT port"); - return NULL; + return FALSE; } port = mm_port_probe_get_port (probe); /* transfer none */ @@ -55,40 +69,15 @@ grab_port (MMPluginBase *base, devfile = g_udev_device_get_device_file (port); if (!devfile) { g_set_error (error, 0, 0, "Could not get port's sysfs file."); - return NULL; - } - - subsys = mm_port_probe_get_port_subsys (probe); - name = mm_port_probe_get_port_name (probe); - - if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) { - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Could not get modem product ID"); - return NULL; - } - - /* If this is the first port being grabbed, create a new modem object */ - if (!existing) - modem = MM_BASE_MODEM (mm_broadband_modem_linktop_new (mm_port_probe_get_port_physdev (probe), - mm_port_probe_get_port_driver (probe), - mm_plugin_get_name (MM_PLUGIN (base)), - vendor, - product)); - - if (!mm_base_modem_grab_port (existing ? existing : modem, - subsys, - name, - MM_PORT_TYPE_AT, /* we only allow AT ports here */ - MM_AT_PORT_FLAG_NONE, - error)) { - if (modem) - g_object_unref (modem); - return NULL; + return FALSE; } - return existing ? existing : modem; + return mm_base_modem_grab_port (modem, + mm_port_probe_get_port_subsys (probe), + mm_port_probe_get_port_name (probe), + MM_PORT_TYPE_AT, /* we only allow AT ports here */ + MM_AT_PORT_FLAG_NONE, + error); } /*****************************************************************************/ @@ -118,5 +107,6 @@ mm_plugin_linktop_class_init (MMPluginLinktopClass *klass) { MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass); + pb_class->create_modem = create_modem; pb_class->grab_port = grab_port; } diff --git a/plugins/motorola/mm-plugin-motorola.c b/plugins/motorola/mm-plugin-motorola.c index ed26430f..f6db862a 100644 --- a/plugins/motorola/mm-plugin-motorola.c +++ b/plugins/motorola/mm-plugin-motorola.c @@ -32,56 +32,42 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; /*****************************************************************************/ static MMBaseModem * +create_modem (MMPluginBase *plugin, + const gchar *sysfs_path, + const gchar *driver, + guint16 vendor, + guint16 product, + GList *probes, + GError **error) +{ + return MM_BASE_MODEM (mm_broadband_modem_motorola_new (sysfs_path, + driver, + mm_plugin_get_name (MM_PLUGIN (plugin)), + vendor, + product)); +} + +static gboolean grab_port (MMPluginBase *base, - MMBaseModem *existing, + MMBaseModem *modem, MMPortProbe *probe, GError **error) { - MMBaseModem *modem = NULL; - const gchar *name, *subsys; - guint16 vendor = 0, product = 0; - /* The Motorola plugin cannot do anything with non-AT ports */ if (!mm_port_probe_is_at (probe)) { g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Ignoring non-AT port"); - return NULL; - } - - subsys = mm_port_probe_get_port_subsys (probe); - name = mm_port_probe_get_port_name (probe); - - if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) { - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Could not get modem product ID"); - return NULL; - } - - /* If this is the first port being grabbed, create a new modem object */ - if (!existing) - modem = MM_BASE_MODEM (mm_broadband_modem_motorola_new ( - mm_port_probe_get_port_physdev (probe), - mm_port_probe_get_port_driver (probe), - mm_plugin_get_name (MM_PLUGIN (base)), - vendor, - product)); - - if (!mm_base_modem_grab_port (existing ? existing : modem, - subsys, - name, - MM_PORT_TYPE_AT, /* we only allow AT ports here */ - MM_AT_PORT_FLAG_NONE, - error)) { - if (modem) - g_object_unref (modem); - return NULL; + return FALSE; } - return existing ? existing : modem; + return mm_base_modem_grab_port (modem, + mm_port_probe_get_port_subsys (probe), + mm_port_probe_get_port_name (probe), + MM_PORT_TYPE_AT, /* we only allow AT ports here */ + MM_AT_PORT_FLAG_NONE, + error); } /*****************************************************************************/ @@ -115,5 +101,6 @@ mm_plugin_motorola_class_init (MMPluginMotorolaClass *klass) { MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass); + pb_class->create_modem = create_modem; pb_class->grab_port = grab_port; } diff --git a/plugins/nokia/mm-plugin-nokia.c b/plugins/nokia/mm-plugin-nokia.c index 7aa102b0..56b649bd 100644 --- a/plugins/nokia/mm-plugin-nokia.c +++ b/plugins/nokia/mm-plugin-nokia.c @@ -12,7 +12,7 @@ * * Copyright (C) 2008 - 2009 Novell, Inc. * Copyright (C) 2009 - 2011 Red Hat, Inc. - * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2011 - 2012 Google, Inc. */ #include <string.h> @@ -42,38 +42,40 @@ static const MMPortProbeAtCommand custom_init[] = { /*****************************************************************************/ static MMBaseModem * +create_modem (MMPluginBase *plugin, + const gchar *sysfs_path, + const gchar *driver, + guint16 vendor, + guint16 product, + GList *probes, + GError **error) +{ + return MM_BASE_MODEM (mm_broadband_modem_nokia_new (sysfs_path, + driver, + mm_plugin_get_name (MM_PLUGIN (plugin)), + vendor, + product)); +} + +static gboolean grab_port (MMPluginBase *base, - MMBaseModem *existing, + MMBaseModem *modem, MMPortProbe *probe, GError **error) { - MMBaseModem *modem = NULL; GUdevDevice *port; - const gchar *name, *subsys, *driver; - guint16 vendor = 0, product = 0; MMAtPortFlag pflags = MM_AT_PORT_FLAG_NONE; - /* The Nokia plugin cannot do anything with non-AT ports */ + /* The Nokia plugin cannot do anything with non-AT */ if (!mm_port_probe_is_at (probe)) { - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_UNSUPPORTED, - "Ignoring non-AT port"); - return NULL; + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_UNSUPPORTED, + "Ignoring non-AT port"); + return FALSE; } port = mm_port_probe_get_port (probe); /* transfer none */ - subsys = mm_port_probe_get_port_subsys (probe); - name = mm_port_probe_get_port_name (probe); - driver = mm_port_probe_get_port_driver (probe); - - if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) { - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Could not get modem product ID"); - return NULL; - } /* Look for port type hints */ if (g_udev_device_get_property_as_boolean (port, "ID_MM_NOKIA_PORT_TYPE_MODEM")) @@ -81,26 +83,12 @@ grab_port (MMPluginBase *base, else if (g_udev_device_get_property_as_boolean (port, "ID_MM_NOKIA_PORT_TYPE_AUX")) pflags = MM_AT_PORT_FLAG_SECONDARY; - /* If this is the first port being grabbed, create a new modem object */ - if (!existing) - modem = MM_BASE_MODEM (mm_broadband_modem_nokia_new (mm_port_probe_get_port_physdev (probe), - driver, - mm_plugin_get_name (MM_PLUGIN (base)), - vendor, - product)); - - if (!mm_base_modem_grab_port (existing ? existing : modem, - subsys, - name, - MM_PORT_TYPE_AT, /* we only allow AT ports here */ - pflags, - error)) { - if (modem) - g_object_unref (modem); - return NULL; - } - - return existing ? existing : modem; + return mm_base_modem_grab_port (modem, + mm_port_probe_get_port_subsys (probe), + mm_port_probe_get_port_name (probe), + mm_port_probe_get_port_type (probe), + pflags, + error); } /*****************************************************************************/ @@ -131,5 +119,6 @@ mm_plugin_nokia_class_init (MMPluginNokiaClass *klass) { MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass); + pb_class->create_modem = create_modem; pb_class->grab_port = grab_port; } diff --git a/plugins/novatel/mm-plugin-novatel.c b/plugins/novatel/mm-plugin-novatel.c index de3fcbf2..a4a0c5ab 100644 --- a/plugins/novatel/mm-plugin-novatel.c +++ b/plugins/novatel/mm-plugin-novatel.c @@ -34,49 +34,40 @@ int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; static MMBaseModem * +create_modem (MMPluginBase *plugin, + const gchar *sysfs_path, + const gchar *driver, + guint16 vendor, + guint16 product, + GList *probes, + GError **error) +{ + return MM_BASE_MODEM (mm_broadband_modem_novatel_new (sysfs_path, + driver, + mm_plugin_get_name (MM_PLUGIN (plugin)), + vendor, + product)); +} + +static gboolean grab_port (MMPluginBase *base, - MMBaseModem *existing, + MMBaseModem *modem, MMPortProbe *probe, GError **error) { - MMBaseModem *modem = NULL; - const gchar *name, *subsys, *driver; - guint16 vendor = 0, product = 0; - /* The Novatel plugin uses AT and net ports */ if (!mm_port_probe_is_at (probe) && !g_str_equal (mm_port_probe_get_port_subsys (probe), "net")) { g_set_error (error, 0, 0, "Ignoring non-AT/net port"); - return NULL; - } - - subsys = mm_port_probe_get_port_subsys (probe); - name = mm_port_probe_get_port_name (probe); - driver = mm_port_probe_get_port_driver (probe); - - /* Try to get Product IDs from udev. */ - mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product); - - /* If this is the first port being grabbed, create a new modem object */ - if (!existing) - modem = MM_BASE_MODEM (mm_broadband_modem_novatel_new (mm_port_probe_get_port_physdev (probe), - driver, - mm_plugin_get_name (MM_PLUGIN (base)), - vendor, - product)); - - if (!mm_base_modem_grab_port (existing ? existing : modem, - subsys, - name, - mm_port_probe_get_port_type (probe), - MM_AT_PORT_FLAG_NONE, - error)) { - if (modem) - g_object_unref (modem); - return NULL; + return FALSE; } - return existing ? existing : modem; + return mm_base_modem_grab_port (modem, + mm_port_probe_get_port_subsys (probe), + mm_port_probe_get_port_name (probe), + mm_port_probe_get_port_type (probe), + MM_AT_PORT_FLAG_NONE, + error); } /*****************************************************************************/ @@ -107,5 +98,6 @@ mm_plugin_novatel_class_init (MMPluginNovatelClass *klass) { MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass); + pb_class->create_modem = create_modem; pb_class->grab_port = grab_port; } diff --git a/plugins/option/mm-plugin-hso.c b/plugins/option/mm-plugin-hso.c index bc04265d..2aa98fdd 100644 --- a/plugins/option/mm-plugin-hso.c +++ b/plugins/option/mm-plugin-hso.c @@ -33,15 +33,29 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; /*****************************************************************************/ static MMBaseModem * +create_modem (MMPluginBase *plugin, + const gchar *sysfs_path, + const gchar *driver, + guint16 vendor, + guint16 product, + GList *probes, + GError **error) +{ + return MM_BASE_MODEM (mm_broadband_modem_hso_new (sysfs_path, + driver, + mm_plugin_get_name (MM_PLUGIN (plugin)), + vendor, + product)); +} + +static gboolean grab_port (MMPluginBase *base, - MMBaseModem *existing, + MMBaseModem *modem, MMPortProbe *probe, GError **error) { - MMBaseModem *modem = NULL; GUdevDevice *port; const gchar *name, *subsys, *sysfs_path; - guint16 vendor = 0, product = 0; MMAtPortFlag pflags = MM_AT_PORT_FLAG_NONE; gchar *devfile; MMPortType port_type; @@ -50,14 +64,6 @@ grab_port (MMPluginBase *base, subsys = mm_port_probe_get_port_subsys (probe); name = mm_port_probe_get_port_name (probe); - if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) { - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Could not get modem product ID"); - return NULL; - } - /* Build proper devfile path * TODO: Why do we need to do this? If this is useful, a comment should be * added explaining why; if it's not useful, let's get rid of it. */ @@ -79,7 +85,7 @@ grab_port (MMPluginBase *base, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Could not get port's sysfs file."); - return NULL; + return FALSE; } } g_free (devfile); @@ -110,26 +116,12 @@ grab_port (MMPluginBase *base, g_free (hsotype_path); } - /* If this is the first port being grabbed, create a new modem object */ - if (!existing) - modem = MM_BASE_MODEM (mm_broadband_modem_hso_new (mm_port_probe_get_port_physdev (probe), - mm_port_probe_get_port_driver (probe), - mm_plugin_get_name (MM_PLUGIN (base)), - vendor, - product)); - - if (!mm_base_modem_grab_port (existing ? existing : modem, - subsys, - name, - port_type, - pflags, - error)) { - if (modem) - g_object_unref (modem); - return NULL; - } - - return existing ? existing : modem; + return mm_base_modem_grab_port (modem, + subsys, + name, + port_type, + pflags, + error); } /*****************************************************************************/ @@ -160,5 +152,6 @@ mm_plugin_hso_class_init (MMPluginHsoClass *klass) { MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass); + pb_class->create_modem = create_modem; pb_class->grab_port = grab_port; } diff --git a/plugins/option/mm-plugin-option.c b/plugins/option/mm-plugin-option.c index 24aed6c0..771cb7b3 100644 --- a/plugins/option/mm-plugin-option.c +++ b/plugins/option/mm-plugin-option.c @@ -32,16 +32,29 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; /*****************************************************************************/ static MMBaseModem * +create_modem (MMPluginBase *plugin, + const gchar *sysfs_path, + const gchar *driver, + guint16 vendor, + guint16 product, + GList *probes, + GError **error) +{ + return MM_BASE_MODEM (mm_broadband_modem_option_new (sysfs_path, + driver, + mm_plugin_get_name (MM_PLUGIN (plugin)), + vendor, + product)); +} + +static gboolean grab_port (MMPluginBase *base, - MMBaseModem *existing, + MMBaseModem *modem, MMPortProbe *probe, GError **error) { - MMBaseModem *modem = NULL; - GUdevDevice *port; - const gchar *name, *subsys, *driver; - guint16 vendor = 0, product = 0; MMAtPortFlag pflags = MM_AT_PORT_FLAG_NONE; + GUdevDevice *port; gint usbif; /* The Option plugin cannot do anything with non-AT ports */ @@ -50,21 +63,10 @@ grab_port (MMPluginBase *base, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Ignoring non-AT port"); - return NULL; + return FALSE; } port = mm_port_probe_get_port (probe); /* transfer none */ - subsys = mm_port_probe_get_port_subsys (probe); - name = mm_port_probe_get_port_name (probe); - driver = mm_port_probe_get_port_driver (probe); - - if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) { - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Could not get modem product ID"); - return NULL; - } /* Genuine Option NV devices are always supposed to use USB interface 0 as * the modem/data port, per mail with Option engineers. Only this port @@ -74,26 +76,12 @@ grab_port (MMPluginBase *base, if (usbif == 0) pflags = MM_AT_PORT_FLAG_PRIMARY | MM_AT_PORT_FLAG_PPP; - /* If this is the first port being grabbed, create a new modem object */ - if (!existing) - modem = MM_BASE_MODEM (mm_broadband_modem_option_new (mm_port_probe_get_port_physdev (probe), - driver, - mm_plugin_get_name (MM_PLUGIN (base)), - vendor, - product)); - - if (!mm_base_modem_grab_port (existing ? existing : modem, - subsys, - name, - MM_PORT_TYPE_AT, /* we only allow AT ports here */ - pflags, - error)) { - if (modem) - g_object_unref (modem); - return NULL; - } - - return existing ? existing : modem; + return mm_base_modem_grab_port (modem, + mm_port_probe_get_port_subsys (probe), + mm_port_probe_get_port_name (probe), + MM_PORT_TYPE_AT, /* we only allow AT ports here */ + pflags, + error); } /*****************************************************************************/ @@ -129,5 +117,6 @@ mm_plugin_option_class_init (MMPluginOptionClass *klass) { MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass); + pb_class->create_modem = create_modem; pb_class->grab_port = grab_port; } diff --git a/plugins/simtech/mm-plugin-simtech.c b/plugins/simtech/mm-plugin-simtech.c index 963da478..7f3bc21a 100644 --- a/plugins/simtech/mm-plugin-simtech.c +++ b/plugins/simtech/mm-plugin-simtech.c @@ -27,20 +27,32 @@ G_DEFINE_TYPE (MMPluginSimtech, mm_plugin_simtech, MM_TYPE_PLUGIN_BASE) int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; - /*****************************************************************************/ static MMBaseModem * +create_modem (MMPluginBase *plugin, + const gchar *sysfs_path, + const gchar *driver, + guint16 vendor, + guint16 product, + GList *probes, + GError **error) +{ + return MM_BASE_MODEM (mm_broadband_modem_simtech_new (sysfs_path, + driver, + mm_plugin_get_name (MM_PLUGIN (plugin)), + vendor, + product)); +} + +static gboolean grab_port (MMPluginBase *base, - MMBaseModem *existing, + MMBaseModem *modem, MMPortProbe *probe, GError **error) { - MMBaseModem *modem = NULL; GUdevDevice *port; MMPortType ptype; - const gchar *name, *subsys; - guint16 vendor = 0, product = 0; MMAtPortFlag pflags = MM_AT_PORT_FLAG_NONE; /* The Simtech plugin cannot do anything with non-AT non-QCDM ports */ @@ -50,20 +62,10 @@ grab_port (MMPluginBase *base, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Ignoring non-AT non-QCDM port"); - return NULL; + return FALSE; } port = mm_port_probe_get_port (probe); /* transfer none */ - subsys = mm_port_probe_get_port_subsys (probe); - name = mm_port_probe_get_port_name (probe); - - if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) { - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Could not get modem product ID"); - return NULL; - } /* Look for port type hints; just probing can't distinguish which port should * be the data/primary port on these devices. We have to tag them based on @@ -84,26 +86,12 @@ grab_port (MMPluginBase *base, else ptype = mm_port_probe_get_port_type (probe); - /* If this is the first port being grabbed, create a new modem object */ - if (!existing) - modem = MM_BASE_MODEM (mm_broadband_modem_simtech_new (mm_port_probe_get_port_physdev (probe), - mm_port_probe_get_port_driver (probe), - mm_plugin_get_name (MM_PLUGIN (base)), - vendor, - product)); - - if (!mm_base_modem_grab_port (existing ? existing : modem, - subsys, - name, - ptype, - pflags, - error)) { - if (modem) - g_object_unref (modem); - return NULL; - } - - return existing ? existing : modem; + return mm_base_modem_grab_port (modem, + mm_port_probe_get_port_subsys (probe), + mm_port_probe_get_port_name (probe), + ptype, + pflags, + error); } /*****************************************************************************/ @@ -135,5 +123,6 @@ mm_plugin_simtech_class_init (MMPluginSimtechClass *klass) { MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass); + pb_class->create_modem = create_modem; pb_class->grab_port = grab_port; } diff --git a/plugins/wavecom/mm-plugin-wavecom.c b/plugins/wavecom/mm-plugin-wavecom.c index d83f96ee..a3e71b26 100644 --- a/plugins/wavecom/mm-plugin-wavecom.c +++ b/plugins/wavecom/mm-plugin-wavecom.c @@ -38,55 +38,42 @@ int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; /*****************************************************************************/ static MMBaseModem * +create_modem (MMPluginBase *plugin, + const gchar *sysfs_path, + const gchar *driver, + guint16 vendor, + guint16 product, + GList *probes, + GError **error) +{ + return MM_BASE_MODEM (mm_broadband_modem_wavecom_new (sysfs_path, + driver, + mm_plugin_get_name (MM_PLUGIN (plugin)), + vendor, + product)); +} + +static gboolean grab_port (MMPluginBase *base, - MMBaseModem *existing, + MMBaseModem *modem, MMPortProbe *probe, GError **error) { - MMBaseModem *modem = NULL; - const gchar *name, *subsys; - guint16 vendor = 0, product = 0; - /* The Wavecom plugin cannot do anything with non-AT ports */ if (!mm_port_probe_is_at (probe)) { g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Ignoring non-AT port"); - return NULL; - } - - subsys = mm_port_probe_get_port_subsys (probe); - name = mm_port_probe_get_port_name (probe); - - if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) { - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Could not get modem product ID"); - return NULL; - } - - /* If this is the first port being grabbed, create a new modem object */ - if (!existing) - modem = MM_BASE_MODEM (mm_broadband_modem_wavecom_new (mm_port_probe_get_port_physdev (probe), - mm_port_probe_get_port_driver (probe), - mm_plugin_get_name (MM_PLUGIN (base)), - vendor, - product)); - - if (!mm_base_modem_grab_port (existing ? existing : modem, - subsys, - name, - MM_PORT_TYPE_AT, /* we only allow AT ports here */ - MM_AT_PORT_FLAG_NONE, - error)) { - if (modem) - g_object_unref (modem); - return NULL; + return FALSE; } - return existing ? existing : modem; + return mm_base_modem_grab_port (modem, + mm_port_probe_get_port_subsys (probe), + mm_port_probe_get_port_name (probe), + MM_PORT_TYPE_AT, /* we only allow AT ports here */ + MM_AT_PORT_FLAG_NONE, + error); } /*****************************************************************************/ @@ -116,5 +103,6 @@ mm_plugin_wavecom_class_init (MMPluginWavecomClass *klass) { MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass); + pb_class->create_modem = create_modem; pb_class->grab_port = grab_port; } diff --git a/src/Makefile.am b/src/Makefile.am index 53b77b76..34dde87c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -148,6 +148,8 @@ ModemManager_SOURCES = \ mm-auth-provider.c \ mm-manager.c \ mm-manager.h \ + mm-device.c \ + mm-device.h \ mm-plugin-manager.c \ mm-plugin-manager.h \ mm-sim.h \ diff --git a/src/mm-device.c b/src/mm-device.c new file mode 100644 index 00000000..3f6859a0 --- /dev/null +++ b/src/mm-device.c @@ -0,0 +1,413 @@ +/* -*- 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) 2012 Google, Inc. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <ModemManager.h> +#include <mm-errors-types.h> + +#include "mm-device.h" + +#include "mm-log.h" + +G_DEFINE_TYPE (MMDevice, mm_device, G_TYPE_OBJECT); + +enum { + PROP_0, + PROP_UDEV_DEVICE, + PROP_PLUGIN, + PROP_MODEM, + PROP_LAST +}; + +static GParamSpec *properties[PROP_LAST]; + +struct _MMDevicePrivate { + /* Parent UDev device */ + GUdevDevice *udev_device; + + /* Best plugin to manage this device */ + MMPlugin *plugin; + + /* List of ports in the device */ + GList *udev_ports; + + /* The Modem object for this device */ + MMBaseModem *modem; + + /* When exported, a reference to the object manager */ + GDBusObjectManagerServer *object_manager; +}; + +/*****************************************************************************/ + +static gint +udev_port_cmp (GUdevDevice *a, + GUdevDevice *b) +{ + return strcmp (g_udev_device_get_sysfs_path (a), + g_udev_device_get_sysfs_path (b)); +} + +gboolean +mm_device_owns_port (MMDevice *self, + GUdevDevice *udev_port) +{ + return !!g_list_find_custom (self->priv->udev_ports, + udev_port, + (GCompareFunc)udev_port_cmp); +} + +void +mm_device_grab_port (MMDevice *self, + GUdevDevice *udev_port) +{ + if (!g_list_find_custom (self->priv->udev_ports, + udev_port, + (GCompareFunc)udev_port_cmp)) { + self->priv->udev_ports = g_list_prepend (self->priv->udev_ports, + g_object_ref (udev_port)); + } +} + +void +mm_device_release_port (MMDevice *self, + GUdevDevice *udev_port) +{ + GList *found; + + found = g_list_find_custom (self->priv->udev_ports, + udev_port, + (GCompareFunc)udev_port_cmp); + if (found) { + g_object_unref (found->data); + self->priv->udev_ports = g_list_delete_link (self->priv->udev_ports, found); + } +} + +/*****************************************************************************/ + +static void +unexport_modem (MMDevice *self) +{ + gchar *path; + + g_assert (MM_IS_BASE_MODEM (self->priv->modem)); + g_assert (G_IS_DBUS_OBJECT_MANAGER (self->priv->object_manager)); + + path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (self->priv->modem))); + if (path != NULL) { + g_dbus_object_manager_server_unexport (self->priv->object_manager, path); + g_object_set (self->priv->modem, + MM_BASE_MODEM_CONNECTION, NULL, + NULL); + + mm_dbg ("Unexported modem '%s' from path '%s'", + g_udev_device_get_sysfs_path (self->priv->udev_device), + path); + g_free (path); + } +} + +/*****************************************************************************/ + +static void +export_modem (MMDevice *self) +{ + GDBusConnection *connection = NULL; + static guint32 id = 0; + gchar *path; + + g_assert (MM_IS_BASE_MODEM (self->priv->modem)); + g_assert (G_IS_DBUS_OBJECT_MANAGER (self->priv->object_manager)); + + /* If modem not yet valid (not fully initialized), don't export it */ + if (!mm_base_modem_get_valid (self->priv->modem)) { + mm_dbg ("Modem '%s' not yet fully initialized", + g_udev_device_get_sysfs_path (self->priv->udev_device)); + return; + } + + /* Don't export already exported modems */ + g_object_get (self->priv->modem, + "g-object-path", &path, + NULL); + if (path) { + g_free (path); + mm_dbg ("Modem '%s' already exported", + g_udev_device_get_sysfs_path (self->priv->udev_device)); + return; + } + + /* No outstanding port tasks, so if the modem is valid we can export it */ + + path = g_strdup_printf (MM_DBUS_MODEM_PREFIX "/%d", id++); + g_object_get (self->priv->object_manager, + "connection", &connection, + NULL); + g_object_set (self->priv->modem, + "g-object-path", path, + MM_BASE_MODEM_CONNECTION, connection, + NULL); + g_object_unref (connection); + + g_dbus_object_manager_server_export (self->priv->object_manager, + G_DBUS_OBJECT_SKELETON (self->priv->modem)); + + mm_dbg ("Exported modem '%s' at path '%s'", + g_udev_device_get_sysfs_path (self->priv->udev_device), + path); + + /* Once connected, dump additional debug info about the modem */ + mm_dbg ("(%s): '%s' modem, VID 0x%04X PID 0x%04X (%s)", + path, + mm_base_modem_get_plugin (self->priv->modem), + (mm_base_modem_get_vendor_id (self->priv->modem) & 0xFFFF), + (mm_base_modem_get_product_id (self->priv->modem) & 0xFFFF), + g_udev_device_get_subsystem (self->priv->udev_device)); + + g_free (path); +} + +/*****************************************************************************/ + +void +mm_device_remove_modem (MMDevice *self) +{ + if (!self->priv->modem) + return; + + unexport_modem (self); + + /* Run dispose before unref-ing, in order to cleanup the SIM object, + * if any (which also holds a reference to the modem object) */ + g_object_run_dispose (G_OBJECT (self->priv->modem)); + g_clear_object (&(self->priv->modem)); + g_clear_object (&(self->priv->object_manager)); +} + +/*****************************************************************************/ + +static void +modem_valid (MMBaseModem *modem, + GParamSpec *pspec, + MMDevice *self) +{ + if (!mm_base_modem_get_valid (modem)) { + /* Modem no longer valid */ + mm_device_remove_modem (self); + } else { + /* Modem now valid, export it */ + export_modem (self); + } +} + +gboolean +mm_device_create_modem (MMDevice *self, + GDBusObjectManagerServer *object_manager, + GError **error) +{ + g_assert (self->priv->modem == NULL); + g_assert (self->priv->object_manager == NULL); + g_assert (self->priv->udev_ports != NULL); + + mm_info ("Creating modem with plugin '%s' and '%u' ports", + mm_plugin_get_name (self->priv->plugin), + g_list_length (self->priv->udev_ports)); + + self->priv->modem = mm_plugin_create_modem (self->priv->plugin, + self->priv->udev_ports, + error); + if (self->priv->modem) { + /* Keep the object manager */ + self->priv->object_manager = g_object_ref (object_manager); + + /* We want to get notified when the modem becomes valid/invalid */ + g_signal_connect (self->priv->modem, + "notify::" MM_BASE_MODEM_VALID, + G_CALLBACK (modem_valid), + self); + } + + return !!self->priv->modem; +} + +/*****************************************************************************/ + +GUdevDevice * +mm_device_peek_udev_device (MMDevice *self) +{ + return self->priv->udev_device; +} + +GUdevDevice * +mm_device_get_udev_device (MMDevice *self) +{ + return G_UDEV_DEVICE (g_object_ref (self->priv->udev_device)); +} + +MMPlugin * +mm_device_peek_plugin (MMDevice *self) +{ + return self->priv->plugin; +} + +MMPlugin * +mm_device_get_plugin (MMDevice *self) +{ + return MM_PLUGIN (g_object_ref (self->priv->plugin)); +} + +MMBaseModem * +mm_device_peek_modem (MMDevice *self) +{ + return (self->priv->modem ? + MM_BASE_MODEM (self->priv->modem) : + NULL); +} + +MMBaseModem * +mm_device_get_modem (MMDevice *self) +{ + return (self->priv->modem ? + MM_BASE_MODEM (g_object_ref (self->priv->modem)) : + NULL); +} + +/*****************************************************************************/ + +MMDevice * +mm_device_new (GUdevDevice *udev_device, + MMPlugin *plugin) +{ + return MM_DEVICE (g_object_new (MM_TYPE_DEVICE, + MM_DEVICE_UDEV_DEVICE, udev_device, + MM_DEVICE_PLUGIN, plugin, + NULL)); +} + +static void +mm_device_init (MMDevice *self) +{ + /* Initialize private data */ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), + MM_TYPE_DEVICE, + MMDevicePrivate); +} + +static void +set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MMDevice *self = MM_DEVICE (object); + + switch (prop_id) { + case PROP_UDEV_DEVICE: + /* construct only */ + self->priv->udev_device = g_value_dup_object (value); + break; + case PROP_PLUGIN: + /* construct only */ + self->priv->plugin = g_value_dup_object (value); + break; + case PROP_MODEM: + g_clear_object (&(self->priv->modem)); + self->priv->modem = 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) +{ + MMDevice *self = MM_DEVICE (object); + + switch (prop_id) { + case PROP_UDEV_DEVICE: + g_value_set_object (value, self->priv->udev_device); + break; + case PROP_PLUGIN: + g_value_set_object (value, self->priv->plugin); + break; + case PROP_MODEM: + g_value_set_object (value, self->priv->modem); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + MMDevice *self = MM_DEVICE (object); + + g_clear_object (&(self->priv->udev_device)); + g_clear_object (&(self->priv->plugin)); + g_list_free_full (self->priv->udev_ports, (GDestroyNotify)g_object_unref); + g_clear_object (&(self->priv->modem)); + + G_OBJECT_CLASS (mm_device_parent_class)->dispose (object); +} + +static void +mm_device_class_init (MMDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (MMDevicePrivate)); + + /* Virtual methods */ + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->dispose = dispose; + + properties[PROP_UDEV_DEVICE] = + g_param_spec_object (MM_DEVICE_UDEV_DEVICE, + "UDev Device", + "UDev device object", + 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]); + + properties[PROP_PLUGIN] = + g_param_spec_object (MM_DEVICE_PLUGIN, + "Plugin", + "Best plugin to manage this device", + MM_TYPE_PLUGIN, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_PLUGIN, properties[PROP_PLUGIN]); + + properties[PROP_MODEM] = + g_param_spec_object (MM_DEVICE_MODEM, + "Modem", + "The modem object", + MM_TYPE_BASE_MODEM, + G_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_MODEM, properties[PROP_MODEM]); +} diff --git a/src/mm-device.h b/src/mm-device.h new file mode 100644 index 00000000..dab11b7e --- /dev/null +++ b/src/mm-device.h @@ -0,0 +1,74 @@ +/* -*- 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) 2012 Google, Inc. + */ + +#ifndef MM_DEVICE_H +#define MM_DEVICE_H + +#include <glib.h> +#include <glib-object.h> + +#include <gudev/gudev.h> + +#include "mm-plugin.h" + +#define MM_TYPE_DEVICE (mm_device_get_type ()) +#define MM_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_DEVICE, MMDevice)) +#define MM_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_DEVICE, MMDeviceClass)) +#define MM_IS_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_DEVICE)) +#define MM_IS_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_DEVICE)) +#define MM_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_DEVICE, MMDeviceClass)) + +typedef struct _MMDevice MMDevice; +typedef struct _MMDeviceClass MMDeviceClass; +typedef struct _MMDevicePrivate MMDevicePrivate; + +#define MM_DEVICE_UDEV_DEVICE "udev-device" +#define MM_DEVICE_PLUGIN "plugin" +#define MM_DEVICE_MODEM "modem" + +struct _MMDevice { + GObject parent; + MMDevicePrivate *priv; +}; + +struct _MMDeviceClass { + GObjectClass parent; +}; + +GType mm_device_get_type (void); + +MMDevice *mm_device_new (GUdevDevice *udev_device, + MMPlugin *plugin); + +void mm_device_grab_port (MMDevice *self, + GUdevDevice *udev_port); +void mm_device_release_port (MMDevice *self, + GUdevDevice *udev_port); +gboolean mm_device_owns_port (MMDevice *self, + GUdevDevice *udev_port); + +gboolean mm_device_create_modem (MMDevice *self, + GDBusObjectManagerServer *object_manager, + GError **error); +void mm_device_remove_modem (MMDevice *self); + +GUdevDevice *mm_device_peek_udev_device (MMDevice *self); +GUdevDevice *mm_device_get_udev_device (MMDevice *self); +MMPlugin *mm_device_peek_plugin (MMDevice *self); +MMPlugin *mm_device_get_plugin (MMDevice *self); +MMBaseModem *mm_device_peek_modem (MMDevice *self); +MMBaseModem *mm_device_get_modem (MMDevice *self); + +#endif /* MM_DEVICE_H */ diff --git a/src/mm-manager.c b/src/mm-manager.c index 7000f038..fc1e4292 100644 --- a/src/mm-manager.c +++ b/src/mm-manager.c @@ -27,17 +27,13 @@ #include <mm-gdbus-manager.h> #include "mm-manager.h" +#include "mm-device.h" #include "mm-plugin-manager.h" #include "mm-auth.h" #include "mm-plugin.h" #include "mm-log.h" #include "mm-port-probe-cache.h" -static void grab_port (MMManager *manager, - MMPlugin *plugin, - GUdevDevice *device, - GUdevDevice *physical_device); - static void initable_iface_init (GInitableIface *iface); G_DEFINE_TYPE_EXTENDED (MMManager, mm_manager, MM_GDBUS_TYPE_ORG_FREEDESKTOP_MODEM_MANAGER1_SKELETON, 0, @@ -60,9 +56,9 @@ struct _MMManagerPrivate { GCancellable *authp_cancellable; /* The Plugin Manager object */ MMPluginManager *plugin_manager; - /* The container of currently available modems */ - GHashTable *modems; - /* DBus The Object Manager server */ + /* The container of devices being prepared */ + GHashTable *devices; + /* The Object Manager server */ GDBusObjectManagerServer *object_manager; }; @@ -95,306 +91,145 @@ find_port_support_context_free (FindPortSupportContext *ctx) g_free (ctx); } -static void -remove_modem (MMManager *manager, - MMBaseModem *modem) -{ - gchar *path; - gchar *device; - - device = g_strdup (mm_base_modem_get_device (modem)); - path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (modem))); - - /* If we get DBus object path, modem was exported */ - if (path) { - g_dbus_object_manager_server_unexport (manager->priv->object_manager, path); - g_object_set (modem, - MM_BASE_MODEM_CONNECTION, NULL, - NULL); - - mm_dbg ("Unexported modem '%s' from path '%s'", device, path); - g_free (path); - } else { - mm_dbg ("Removing modem '%s', which wasn't exported yet", device); - } - - /* Run dispose before unref-ing, in order to cleanup the SIM object, - * if any (which also holds a reference to the modem object) */ - g_object_run_dispose (G_OBJECT (modem)); - g_hash_table_remove (manager->priv->modems, device); - g_free (device); -} - -static void -debug_modem_info (MMManager *self, - MMBaseModem *modem, - const gchar *path) -{ - GUdevDevice *physdev; - const gchar *subsys; - - physdev = g_udev_client_query_by_sysfs_path (self->priv->udev, - mm_base_modem_get_device (modem)); - subsys = (physdev ? - g_udev_device_get_subsystem (physdev) : - NULL); - - mm_dbg ("(%s): '%s' modem, VID 0x%04X PID 0x%04X (%s)", - path, - mm_base_modem_get_plugin (modem), - (mm_base_modem_get_vendor_id (modem) & 0xFFFF), - (mm_base_modem_get_product_id (modem) & 0xFFFF), - subsys ? subsys : "unknown"); - - if (physdev) - g_object_unref (physdev); -} - -static void -check_export_modem (MMManager *self, - MMBaseModem *modem) -{ - GError *error = NULL; - static guint32 id = 0; - const gchar *modem_physdev; - const gchar *name; - const gchar *subsys; - gchar *path; - - /* A modem is only exported to D-Bus when both of the following are true: - * - * 1) the modem is valid - * 2) all ports the modem provides have either been grabbed or are - * unsupported by any plugin - * - * This ensures that all the modem's ports are completely ready before - * any clients can do anything with it. - * - * FIXME: if udev or the kernel are really slow giving us ports, there's a - * chance that a port could show up after the modem is already created and - * all other ports are already handled. That chance is very small though. - */ - - modem_physdev = mm_base_modem_get_device (modem); - g_assert (modem_physdev); - - /* Check for ports that are in the process of being interrogated by plugins */ - if (mm_plugin_manager_is_finding_device_support (self->priv->plugin_manager, - modem_physdev, - &subsys, - &name)) { - mm_dbg ("(%s/%s): outstanding support task prevents export of '%s'", - subsys, name, modem_physdev); - return; - } - - /* Plugin manager is not trying to find more ports supported by this device, - * so we can organize the ports now (if not done already). */ - if (!mm_base_modem_organize_ports (modem, &error)) { - /* If the ports were not properly organized, the modem will be marked as - * invalid and therefore removed */ - mm_err ("Failed to organize modem ports: '%s'", - error->message); - g_error_free (error); - remove_modem (self, modem); - return; - } - - /* If modem not yet valid (not fully initialized), don't export it */ - if (!mm_base_modem_get_valid (modem)) - return; - - /* Don't export already exported modems */ - g_object_get (modem, - "g-object-path", &path, - NULL); - if (path) { - g_free (path); - mm_dbg ("Modem '%s' already exported", modem_physdev); - return; - } - - /* No outstanding port tasks, so if the modem is valid we can export it */ - path = g_strdup_printf (MM_DBUS_MODEM_PREFIX "/%d", id++); - g_object_set (modem, - "g-object-path", path, - MM_BASE_MODEM_CONNECTION, self->priv->connection, - NULL); - g_dbus_object_manager_server_export (self->priv->object_manager, - G_DBUS_OBJECT_SKELETON (modem)); - mm_dbg ("Exported modem '%s' at path '%s'", modem_physdev, path); - - /* Once connected, dump additional debug info about the modem */ - debug_modem_info (self, modem, path); - g_free (path); -} - -static void -modem_valid (MMBaseModem *modem, - GParamSpec *pspec, - gpointer user_data) -{ - MMManager *manager = MM_MANAGER (user_data); - - if (mm_base_modem_get_valid (modem)) - check_export_modem (manager, modem); - else - remove_modem (manager, modem); -} - -#define MANAGER_PLUGIN_TAG "manager-plugin" - -static void -add_modem (MMManager *manager, - MMBaseModem *modem, - MMPlugin *plugin) -{ - const gchar *device; - - device = mm_base_modem_get_device (modem); - if (!g_hash_table_lookup (manager->priv->modems, device)) { - mm_dbg ("Added modem %s", device); - g_hash_table_insert (manager->priv->modems, - g_strdup (device), - modem); - g_object_set_data (G_OBJECT (modem), MANAGER_PLUGIN_TAG, plugin); - g_signal_connect (modem, "notify::" MM_BASE_MODEM_VALID, G_CALLBACK (modem_valid), manager); - } - - check_export_modem (manager, modem); -} - -static MMBaseModem * -find_modem_for_device (MMManager *manager, - const gchar *device) +static MMDevice * +find_device_by_modem (MMManager *manager, + MMBaseModem *modem) { GHashTableIter iter; gpointer key, value; - g_hash_table_iter_init (&iter, manager->priv->modems); + g_hash_table_iter_init (&iter, manager->priv->devices); while (g_hash_table_iter_next (&iter, &key, &value)) { - MMBaseModem *candidate = MM_BASE_MODEM (value); + MMDevice *candidate = MM_DEVICE (value); - if (g_str_equal (device, - mm_base_modem_get_device (candidate))) + if (modem == mm_device_peek_modem (candidate)) return candidate; } - return NULL; } -static MMBaseModem * -find_modem_for_port (MMManager *manager, - const gchar *subsys, - const gchar *name) +static MMDevice * +find_device_by_port (MMManager *manager, + GUdevDevice *port) { GHashTableIter iter; gpointer key, value; - g_hash_table_iter_init (&iter, manager->priv->modems); + g_hash_table_iter_init (&iter, manager->priv->devices); while (g_hash_table_iter_next (&iter, &key, &value)) { - MMBaseModem *candidate = MM_BASE_MODEM (value); + MMDevice *candidate = MM_DEVICE (value); - if (mm_base_modem_owns_port (candidate, subsys, name)) + if (mm_device_owns_port (candidate, port)) return candidate; } return NULL; } +static MMDevice * +find_device_by_sysfs_path (MMManager *self, + const gchar *sysfs_path) +{ + return g_hash_table_lookup (self->priv->devices, + sysfs_path); +} + +static MMDevice * +find_device_by_udev_device (MMManager *manager, + GUdevDevice *udev_device) +{ + return find_device_by_sysfs_path (manager, g_udev_device_get_sysfs_path (udev_device)); +} + static void find_port_support_ready_cb (MMPluginManager *plugin_manager, GAsyncResult *result, FindPortSupportContext *ctx) { GError *error = NULL; + MMDevice *device; MMPlugin *best_plugin; + /* Look for the container device, if any */ + device = find_device_by_udev_device (ctx->manager, ctx->physical_device); + best_plugin = mm_plugin_manager_find_port_support_finish (plugin_manager, result, &error); if (!best_plugin) { - MMBaseModem *existing; - if (error) { - mm_dbg ("(%s/%s): error checking support: '%s'", - g_udev_device_get_subsystem (ctx->device), - g_udev_device_get_name (ctx->device), - error->message); + mm_warn ("(%s/%s): error checking support: '%s'", + g_udev_device_get_subsystem (ctx->device), + g_udev_device_get_name (ctx->device), + error->message); g_error_free (error); } else { mm_dbg ("(%s/%s): not supported by any plugin", g_udev_device_get_subsystem (ctx->device), g_udev_device_get_name (ctx->device)); } - - /* So we couldn't get a plugin for this port, we should anyway check if - * there is already an existing modem for the physical device, and if - * so, check if it can already be exported. */ - existing = find_modem_for_device ( - ctx->manager, - g_udev_device_get_sysfs_path (ctx->physical_device)); - if (existing) - check_export_modem (ctx->manager, existing); } else { - mm_dbg ("(%s/%s): found plugin '%s' giving best support", + /* Found a best plugin for the port */ + + if (!device) { + /* Create a generic device to track the available ports, and add it to the + * manager. */ + device = mm_device_new (ctx->physical_device, + best_plugin); + g_hash_table_insert (ctx->manager->priv->devices, + g_strdup (g_udev_device_get_sysfs_path (mm_device_peek_udev_device (device))), + device); + } + else if (!g_str_equal (mm_plugin_get_name (mm_device_peek_plugin (device)), + mm_plugin_get_name (best_plugin))) { + /* Warn if the best plugin found for this port differs from the + * best plugin found for the the first grabbed port */ + mm_warn ("(%s/%s): plugin mismatch error (expected: '%s', got: '%s')", + g_udev_device_get_subsystem (ctx->device), + g_udev_device_get_name (ctx->device), + mm_plugin_get_name (mm_device_peek_plugin (device)), + mm_plugin_get_name (best_plugin)); + } + + /* Add the port to the device */ + mm_dbg ("(%s/%s): added to device managed by plugin '%s'", g_udev_device_get_subsystem (ctx->device), g_udev_device_get_name (ctx->device), - mm_plugin_get_name ((MMPlugin *)best_plugin)); - - grab_port (ctx->manager, - best_plugin, - ctx->device, - ctx->physical_device); + mm_plugin_get_name (mm_device_peek_plugin (device))); + mm_device_grab_port (device, ctx->device); } - find_port_support_context_free (ctx); -} + if (device) { + const gchar *subsys; + const gchar *name; -static void -grab_port (MMManager *manager, - MMPlugin *plugin, - GUdevDevice *device, - GUdevDevice *physical_device) -{ - GError *error = NULL; - MMBaseModem *modem; - MMBaseModem *existing; - - existing = g_hash_table_lookup (manager->priv->modems, - g_udev_device_get_sysfs_path (physical_device)); - - /* While grabbing the first port, modem will get created */ - modem = mm_plugin_grab_port (plugin, - g_udev_device_get_subsystem (device), - g_udev_device_get_name (device), - existing, - &error); - if (!modem) { - mm_warn ("plugin '%s' claimed to support %s/%s but couldn't: (%d) %s", - mm_plugin_get_name (plugin), - g_udev_device_get_subsystem (device), - g_udev_device_get_name (device), - error ? error->code : -1, - (error && error->message) ? error->message : "(unknown)"); - g_clear_error (&error); - - if (existing) - check_export_modem (manager, existing); - return; + /* This port was probed after having created the modem */ + if (mm_device_peek_modem (device)) { + mm_dbg ("(%s/%s): port added to existing modem", + g_udev_device_get_subsystem (ctx->device), + g_udev_device_get_name (ctx->device)); + } + /* Every time we get a supports check result, we need to see if there + * are ports of the same device still being probed. */ + else if (mm_plugin_manager_is_finding_device_support (plugin_manager, + g_udev_device_get_sysfs_path (mm_device_peek_udev_device (device)), + &subsys, + &name)) { + mm_dbg ("(%s/%s): outstanding support task prevents export of '%s'", + subsys, name, g_udev_device_get_sysfs_path (mm_device_peek_udev_device (device))); + } + /* Plugin manager is not trying to find more ports supported by this + * device, so we can create the modem now! */ + else { + if (!mm_device_create_modem (device, ctx->manager->priv->object_manager, &error)) { + mm_warn ("Couldn't create '%s' modem for device at '%s': %s", + g_udev_device_get_sysfs_path (mm_device_peek_udev_device (device)), + mm_plugin_get_name (mm_device_peek_plugin (device)), + error ? error->message : "Unknown error"); + } + } } - mm_info ("(%s): modem %s claimed port %s", - mm_plugin_get_name (plugin), - mm_base_modem_get_device (modem), - g_udev_device_get_name (device)); - - if (existing) { - g_assert (existing == modem); - check_export_modem (manager, modem); - } else { - /* If the modem was just created, store it */ - add_modem (manager, modem, plugin); - } + find_port_support_context_free (ctx); } static GUdevDevice * @@ -461,18 +296,17 @@ find_physical_device (GUdevDevice *child) static void device_added (MMManager *manager, - GUdevDevice *device) + GUdevDevice *port) { const char *subsys, *name, *physdev_path, *physdev_subsys; gboolean is_candidate; GUdevDevice *physdev = NULL; - MMPlugin *plugin; - MMBaseModem *existing; + MMDevice *existing; - g_return_if_fail (device != NULL); + g_return_if_fail (port != NULL); - subsys = g_udev_device_get_subsystem (device); - name = g_udev_device_get_name (device); + subsys = g_udev_device_get_subsystem (port); + name = g_udev_device_get_name (port); /* ignore VTs */ if (strncmp (name, "tty", 3) == 0 && isdigit (name[3])) @@ -485,18 +319,18 @@ device_added (MMManager *manager, * the device to a specific ModemManager driver, we need to ensure that all * rules have been processed before handling a device. */ - is_candidate = g_udev_device_get_property_as_boolean (device, "ID_MM_CANDIDATE"); + is_candidate = g_udev_device_get_property_as_boolean (port, "ID_MM_CANDIDATE"); if (!is_candidate) return; - if (find_modem_for_port (manager, subsys, name)) + if (find_device_by_port (manager, port)) return; /* Find the port's physical device's sysfs path. This is the kernel device * that "owns" all the ports of the device, like the USB device or the PCI * device the provides each tty or network port. */ - physdev = find_physical_device (device); + physdev = find_physical_device (port); if (!physdev) { /* Warn about it, but filter out some common ports that we know don't have * anything to do with mobile broadband. @@ -545,10 +379,7 @@ device_added (MMManager *manager, * asking all plugins whether they support this port, just let the owning * plugin check if it supports the port. */ - existing = find_modem_for_device (manager, physdev_path); - plugin = (existing ? - MM_PLUGIN (g_object_get_data (G_OBJECT (existing), MANAGER_PLUGIN_TAG)) : - NULL); + existing = find_device_by_udev_device (manager, physdev); /* Launch supports check in the Plugin Manager */ mm_plugin_manager_find_port_support ( @@ -556,12 +387,12 @@ device_added (MMManager *manager, subsys, name, physdev_path, - plugin, - existing, + existing ? mm_device_peek_plugin (existing) : NULL, + existing ? mm_device_peek_modem (existing) : NULL, (GAsyncReadyCallback)find_port_support_ready_cb, find_port_support_context_new (manager, - device, - physdev)); + port, + physdev)); out: if (physdev) @@ -569,48 +400,45 @@ out: } static void -device_removed (MMManager *manager, - GUdevDevice *device) +device_removed (MMManager *self, + GUdevDevice *udev_device) { - MMBaseModem *modem; - const char *subsys, *name; + MMDevice *device; - g_return_if_fail (device != NULL); - - subsys = g_udev_device_get_subsystem (device); - name = g_udev_device_get_name (device); + g_return_if_fail (udev_device != NULL); /* Ensure cached port probe infos get removed when the port is gone */ - mm_port_probe_cache_remove (device); + mm_port_probe_cache_remove (udev_device); - if (strcmp (subsys, "usb") != 0) { - /* find_modem_for_port handles tty and net removal */ - modem = find_modem_for_port (manager, subsys, name); - if (modem) { + if (!g_str_equal (g_udev_device_get_subsystem (udev_device), "usb")) { + /* Handle tty/net port removal */ + device = find_device_by_port (self, udev_device); + if (device) { mm_info ("(%s/%s): released by modem %s", - subsys, - name, - mm_base_modem_get_device (modem)); - mm_base_modem_release_port (modem, subsys, name); - return; + g_udev_device_get_subsystem (udev_device), + g_udev_device_get_name (udev_device), + g_udev_device_get_sysfs_path (mm_device_peek_udev_device (device))); + mm_device_release_port (device, udev_device); } - } else { - /* This case is designed to handle the case where, at least with kernel 2.6.31, unplugging - * an in-use ttyACMx device results in udev generating remove events for the usb, but the - * ttyACMx device (subsystem tty) is not removed, since it was in-use. So if we have not - * found a modem for the port (above), we're going to look here to see if we have a modem - * associated with the newly removed device. If so, we'll remove the modem, since the - * device has been removed. That way, if the device is reinserted later, we'll go through - * the process of exporting it. - */ - const char *sysfs_path = g_udev_device_get_sysfs_path (device); - modem = find_modem_for_device (manager, sysfs_path); - if (modem) { - mm_dbg ("Removing modem claimed by removed device %s", sysfs_path); - remove_modem (manager, modem); - return; - } + return; + } + + /* This case is designed to handle the case where, at least with kernel 2.6.31, unplugging + * an in-use ttyACMx device results in udev generating remove events for the usb, but the + * ttyACMx device (subsystem tty) is not removed, since it was in-use. So if we have not + * found a modem for the port (above), we're going to look here to see if we have a modem + * associated with the newly removed device. If so, we'll remove the modem, since the + * device has been removed. That way, if the device is reinserted later, we'll go through + * the process of exporting it. + */ + device = find_device_by_udev_device (self, udev_device); + if (device) { + mm_dbg ("Removing device %s", + g_udev_device_get_sysfs_path (mm_device_peek_udev_device (device))); + mm_device_remove_modem (device); + g_hash_table_remove (self->priv->devices, device); + return; } /* Maybe a plugin is checking whether or not the port is supported. @@ -631,7 +459,6 @@ handle_uevent (GUdevClient *client, /* A bit paranoid */ subsys = g_udev_device_get_subsystem (device); g_return_if_fail (subsys != NULL); - g_return_if_fail (!strcmp (subsys, "tty") || !strcmp (subsys, "net") || !strcmp (subsys, "usb")); /* We only care about tty/net devices when adding modem ports, @@ -676,17 +503,28 @@ remove_disable_ready (MMBaseModem *modem, GAsyncResult *res, MMManager *self) { + MMDevice *device; + /* We don't care about errors disabling at this point */ mm_base_modem_disable_finish (modem, res, NULL); - remove_modem (self, modem); + + device = find_device_by_modem (self, modem); + if (device) { + mm_device_remove_modem (device); + g_hash_table_remove (self->priv->devices, device); + } } static void foreach_disable (gpointer key, - MMBaseModem *modem, + MMDevice *device, MMManager *self) { - mm_base_modem_disable (modem, (GAsyncReadyCallback)remove_disable_ready, self); + MMBaseModem *modem; + + modem = mm_device_peek_modem (device); + if (modem) + mm_base_modem_disable (modem, (GAsyncReadyCallback)remove_disable_ready, self); } void @@ -698,7 +536,7 @@ mm_manager_shutdown (MMManager *self) /* Cancel all ongoing auth requests */ g_cancellable_cancel (self->priv->authp_cancellable); - g_hash_table_foreach (self->priv->modems, (GHFunc)foreach_disable, self); + g_hash_table_foreach (self->priv->devices, (GHFunc)foreach_disable, self); /* Disabling may take a few iterations of the mainloop, so the caller * has to iterate the mainloop until all devices have been disabled and @@ -709,10 +547,20 @@ mm_manager_shutdown (MMManager *self) guint32 mm_manager_num_modems (MMManager *self) { + GHashTableIter iter; + gpointer key, value; + guint32 n; + g_return_val_if_fail (self != NULL, 0); g_return_val_if_fail (MM_IS_MANAGER (self), 0); - return g_hash_table_size (self->priv->modems); + n = 0; + g_hash_table_iter_init (&iter, self->priv->devices); + while (g_hash_table_iter_next (&iter, &key, &value)) { + n += !!mm_device_peek_modem (MM_DEVICE (value)); + } + + return n; } /*****************************************************************************/ @@ -894,8 +742,8 @@ mm_manager_init (MMManager *manager) priv->authp = mm_auth_get_provider (); priv->authp_cancellable = g_cancellable_new (); - /* Setup internal list of modem objects */ - priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + /* Setup internal lists of device objects */ + priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); /* Setup UDev client */ priv->udev = g_udev_client_new (subsys); @@ -947,7 +795,7 @@ finalize (GObject *object) { MMManagerPrivate *priv = MM_MANAGER (object)->priv; - g_hash_table_destroy (priv->modems); + g_hash_table_destroy (priv->devices); mm_port_probe_cache_clear (); diff --git a/src/mm-plugin-base.c b/src/mm-plugin-base.c index f5b0bd11..3a289582 100644 --- a/src/mm-plugin-base.c +++ b/src/mm-plugin-base.c @@ -759,30 +759,86 @@ supports_port_cancel (MMPlugin *plugin, } static MMBaseModem * -grab_port (MMPlugin *plugin, - const char *subsys, - const char *name, - MMBaseModem *existing, - GError **error) +create_modem (MMPlugin *self, + GList *ports, + GError **error) { - MMPluginBase *self = MM_PLUGIN_BASE (plugin); - MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self); - MMPortProbe *probe; MMBaseModem *modem = NULL; - char *key; + MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self); + GList *probes = NULL; + GList *l; + const gchar *name, *subsys, *sysfs_path, *driver; + guint16 vendor = 0, product = 0; + + /* Get the port probe results for each of the ports */ + for (l = ports; l; l = g_list_next (l)) { + MMPortProbe *probe; + gchar *key; - key = get_key (subsys, name); - probe = g_hash_table_lookup (priv->tasks, key); - g_assert (probe); + subsys = g_udev_device_get_subsystem (G_UDEV_DEVICE (l->data)); + name = g_udev_device_get_name (G_UDEV_DEVICE (l->data)); - /* Let the modem grab the port */ - modem = MM_PLUGIN_BASE_GET_CLASS (self)->grab_port (self, - existing, - probe, - error); + key = get_key (subsys, name); + probe = g_hash_table_lookup (priv->tasks, key); + g_assert (probe); + probes = g_list_prepend (probes, g_object_ref (probe)); + g_free (key); + } + + /* Get info from the first probe in the list */ + subsys = mm_port_probe_get_port_subsys (probes->data); + name = mm_port_probe_get_port_name (probes->data); + sysfs_path = mm_port_probe_get_port_physdev (probes->data); + driver = mm_port_probe_get_port_driver (probes->data); + + /* Vendor and Product IDs are really optional, we'll just warn if they + * cannot get loaded */ + if (!mm_plugin_base_get_device_ids (MM_PLUGIN_BASE (self), subsys, name, &vendor, &product)) + mm_warn ("Could not get modem vendor/product ID"); + + /* Let the plugin create the modem from the port probe results */ + modem = MM_PLUGIN_BASE_GET_CLASS (self)->create_modem (MM_PLUGIN_BASE (self), + sysfs_path, + driver, + vendor, + product, + probes, + error); + if (modem) { + /* Grab each port */ + for (l = probes; l; l = g_list_next (l)) { + GError *inner_error = NULL; + + /* If grabbing a port fails, just warn. We'll decide if the modem is + * valid or not when all ports get organized */ + if (!MM_PLUGIN_BASE_GET_CLASS (self)->grab_port (MM_PLUGIN_BASE (self), + modem, + MM_PORT_PROBE (l->data), + &inner_error)) { + mm_warn ("Could not grab port (%s/%s): '%s'", + mm_port_probe_get_port_subsys (MM_PORT_PROBE (l->data)), + mm_port_probe_get_port_name (MM_PORT_PROBE (l->data)), + inner_error ? inner_error->message : "unknown error"); + g_clear_error (&inner_error); + } + } + + /* If organizing ports fails, consider the modem invalid */ + if (!mm_base_modem_organize_ports (modem, error)) + g_clear_object (&modem); + } + + for (l = probes; l; l = g_list_next (l)) { + gchar *key; + + key = get_key (mm_port_probe_get_port_subsys (l->data), + mm_port_probe_get_port_name (l->data)); + g_hash_table_remove (priv->tasks, key); + g_free (key); + } + + g_list_free_full (probes, (GDestroyNotify) g_object_unref); - g_hash_table_remove (priv->tasks, key); - g_free (key); return modem; } @@ -797,7 +853,7 @@ plugin_init (MMPlugin *plugin_class) plugin_class->supports_port = supports_port; plugin_class->supports_port_finish = supports_port_finish; plugin_class->supports_port_cancel = supports_port_cancel; - plugin_class->grab_port = grab_port; + plugin_class->create_modem = create_modem; } static void @@ -1073,5 +1129,5 @@ mm_plugin_base_class_init (MMPluginBaseClass *klass) "Send delay for characters in the AT port, " "in microseconds", 0, G_MAXUINT64, 100000, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } diff --git a/src/mm-plugin-base.h b/src/mm-plugin-base.h index 3870fd89..c5d9bbad 100644 --- a/src/mm-plugin-base.h +++ b/src/mm-plugin-base.h @@ -58,10 +58,19 @@ struct _MMPluginBaseClass { GObjectClass parent; /* Mandatory subclass functions */ - MMBaseModem *(*grab_port) (MMPluginBase *plugin, - MMBaseModem *existing, - MMPortProbe *probe, - GError **error); + + MMBaseModem *(*create_modem) (MMPluginBase *plugin, + const gchar *sysfs_path, + const gchar *driver, + guint16 vendor, + guint16 product, + GList *probes, + GError **error); + + gboolean (*grab_port) (MMPluginBase *plugin, + MMBaseModem *modem, + MMPortProbe *probe, + GError **error); }; GType mm_plugin_base_get_type (void); diff --git a/src/mm-plugin.c b/src/mm-plugin.c index 950efc4c..6418e295 100644 --- a/src/mm-plugin.c +++ b/src/mm-plugin.c @@ -84,17 +84,14 @@ mm_plugin_supports_port_cancel (MMPlugin *plugin, } MMBaseModem * -mm_plugin_grab_port (MMPlugin *plugin, - const char *subsys, - const char *name, - MMBaseModem *existing, - GError **error) +mm_plugin_create_modem (MMPlugin *plugin, + GList *ports, + GError **error) { - g_return_val_if_fail (MM_IS_PLUGIN (plugin), FALSE); - g_return_val_if_fail (subsys != NULL, FALSE); - g_return_val_if_fail (name != NULL, FALSE); + if (MM_PLUGIN_GET_INTERFACE (plugin)->create_modem) + return MM_PLUGIN_GET_INTERFACE (plugin)->create_modem (plugin, ports, error); - return MM_PLUGIN_GET_INTERFACE (plugin)->grab_port (plugin, subsys, name, existing, error); + return NULL; } /*****************************************************************************/ diff --git a/src/mm-plugin.h b/src/mm-plugin.h index 71120112..d31be1e4 100644 --- a/src/mm-plugin.h +++ b/src/mm-plugin.h @@ -83,19 +83,10 @@ struct _MMPlugin { const char *subsys, const char *name); - /* Will only be called if the plugin returns a value greater than 0 for - * the supports_port() method for this port. The plugin should create and - * return a new modem for the port's device if there is no existing modem - * to handle the port's hardware device, or should add the port to an - * existing modem and return that modem object. If an error is encountered - * while claiming the port, the error information should be returned in the - * error argument, and the plugin should return NULL. - */ - MMBaseModem * (*grab_port) (MMPlugin *self, - const char *subsys, - const char *name, - MMBaseModem *existing, - GError **error); + /* Given all the list of ports, launch creation of a new modem object */ + MMBaseModem * (*create_modem) (MMPlugin *self, + GList *ports, + GError **error); }; GType mm_plugin_get_type (void); @@ -120,10 +111,8 @@ void mm_plugin_supports_port_cancel (MMPlugin *plugin, const char *subsys, const char *name); -MMBaseModem *mm_plugin_grab_port (MMPlugin *plugin, - const char *subsys, - const char *name, - MMBaseModem *existing, +MMBaseModem *mm_plugin_create_modem (MMPlugin *plugin, + GList *ports, GError **error); #endif /* MM_PLUGIN_H */ |