diff options
-rw-r--r-- | introspection/mm-modem.xml | 12 | ||||
-rw-r--r-- | src/mm-generic-cdma.c | 44 | ||||
-rw-r--r-- | src/mm-generic-gsm.c | 62 | ||||
-rw-r--r-- | src/mm-modem-base.c | 83 | ||||
-rw-r--r-- | src/mm-modem-helpers.c | 65 | ||||
-rw-r--r-- | src/mm-modem-helpers.h | 10 | ||||
-rw-r--r-- | src/mm-modem.c | 8 | ||||
-rw-r--r-- | src/mm-modem.h | 4 | ||||
-rwxr-xr-x | test/info.py | 1 |
9 files changed, 257 insertions, 32 deletions
diff --git a/introspection/mm-modem.xml b/introspection/mm-modem.xml index 7d54dd30..9391bad5 100644 --- a/introspection/mm-modem.xml +++ b/introspection/mm-modem.xml @@ -98,6 +98,18 @@ </tp:docstring> </property> + <property name="DeviceIdentifier" type="s" access="read"> + <tp:docstring> + A best-effort device identifier based on various device information like + model name, firmware revision, USB/PCI/PCMCIA IDs, and other properties. + This ID is not guaranteed to be unique and may be shared between + identical devices with the same firmware, but is intended to be + "unique enough" for use as a casual device identifier for various + user experience operations. This is not the device's IMEI or ESN since + those may not be available before unlocking the device via a PIN. + </tp:docstring> + </property> + <property name="MasterDevice" type="s" access="read"> <tp:docstring> The physical modem device reference (ie, USB, PCI, PCMCIA device), which diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index 3dc3de4d..4dd1f0ef 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -162,6 +162,47 @@ initial_esn_check (MMGenericCdma *self) } } +static void +get_info_cb (MMModem *modem, + const char *manufacturer, + const char *model, + const char *version, + GError *error, + gpointer user_data) +{ + /* Base class handles saving the info for us */ + if (modem) + mm_serial_port_close (MM_SERIAL_PORT (MM_GENERIC_CDMA_GET_PRIVATE (modem)->primary)); +} + +static void +initial_info_check (MMGenericCdma *self) +{ + GError *error = NULL; + MMGenericCdmaPrivate *priv; + + g_return_if_fail (MM_IS_GENERIC_CDMA (self)); + priv = MM_GENERIC_CDMA_GET_PRIVATE (self); + + g_return_if_fail (priv->primary != NULL); + + if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) { + /* Make sure echoing is off */ + mm_at_serial_port_queue_command (priv->primary, "E0", 3, NULL, NULL); + mm_modem_base_get_card_info (MM_MODEM_BASE (self), + priv->primary, + NULL, + get_info_cb, + NULL); + } else { + g_warning ("%s: failed to open serial port: (%d) %s", + __func__, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } +} + static gboolean owns_port (MMModem *modem, const char *subsys, const char *name) { @@ -215,6 +256,9 @@ mm_generic_cdma_grab_port (MMGenericCdma *self, g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE); } + /* Get the modem's general info */ + initial_info_check (self); + /* Get modem's ESN number */ initial_esn_check (self); diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index 0bdeec42..dbbd189a 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -326,6 +326,19 @@ get_imei_cb (MMModem *modem, } } +static void +get_info_cb (MMModem *modem, + const char *manufacturer, + const char *model, + const char *version, + GError *error, + gpointer user_data) +{ + /* Base class handles saving the info for us */ + if (modem) + mm_serial_port_close (MM_SERIAL_PORT (MM_GENERIC_GSM_GET_PRIVATE (modem)->primary)); +} + /*****************************************************************************/ static MMModemGsmNetworkRegStatus @@ -510,6 +523,34 @@ initial_imei_check (MMGenericGsm *self) } } +static void +initial_info_check (MMGenericGsm *self) +{ + GError *error = NULL; + MMGenericGsmPrivate *priv; + + g_return_if_fail (MM_IS_GENERIC_GSM (self)); + priv = MM_GENERIC_GSM_GET_PRIVATE (self); + + g_return_if_fail (priv->primary != NULL); + + if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) { + /* Make sure echoing is off */ + mm_at_serial_port_queue_command (priv->primary, "E0", 3, NULL, NULL); + mm_modem_base_get_card_info (MM_MODEM_BASE (self), + priv->primary, + NULL, + get_info_cb, + NULL); + } else { + g_warning ("%s: failed to open serial port: (%d) %s", + __func__, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } +} + static gboolean owns_port (MMModem *modem, const char *subsys, const char *name) { @@ -560,12 +601,15 @@ mm_generic_gsm_grab_port (MMGenericGsm *self, g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE); } - /* Get modem's initial lock/unlock state */ - initial_pin_check (self); + /* Get the modem's general info */ + initial_info_check (self); /* Get modem's IMEI number */ initial_imei_check (self); + /* Get modem's initial lock/unlock state */ + initial_pin_check (self); + } else if (ptype == MM_PORT_TYPE_SECONDARY) priv->secondary = MM_AT_SERIAL_PORT (port); } else if (MM_IS_QCDM_SERIAL_PORT (port)) { @@ -937,17 +981,6 @@ get_allowed_mode_done (MMModem *modem, } } -static void -get_enable_info_done (MMModem *modem, - const char *manufacturer, - const char *model, - const char *version, - GError *error, - gpointer user_data) -{ - /* Modem base class handles the response for us */ -} - void mm_generic_gsm_enable_complete (MMGenericGsm *self, GError *error, @@ -985,9 +1018,6 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self, /* Try to enable XON/XOFF flow control */ mm_at_serial_port_queue_command (priv->primary, "+IFC=1,1", 3, NULL, NULL); - /* Grab device info right away */ - mm_modem_get_info (MM_MODEM (self), get_enable_info_done, NULL); - /* Get allowed mode */ if (MM_GENERIC_GSM_GET_CLASS (self)->get_allowed_mode) MM_GENERIC_GSM_GET_CLASS (self)->get_allowed_mode (self, get_allowed_mode_done, NULL); diff --git a/src/mm-modem-base.c b/src/mm-modem-base.c index 6c755479..b7bdb6ea 100644 --- a/src/mm-modem-base.c +++ b/src/mm-modem-base.c @@ -14,6 +14,7 @@ * Copyright (C) 2009 Red Hat, Inc. */ +#include <config.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -43,6 +44,7 @@ typedef struct { char *plugin; char *device; char *equipment_ident; + char *device_ident; char *unlock_required; guint32 unlock_retries; guint32 ip_method; @@ -52,6 +54,9 @@ typedef struct { char *manf; char *model; char *revision; + char *ati; + char *ati1; + char *gsn; MMAuthProvider *authp; @@ -396,7 +401,7 @@ card_info_cache_invoke (MMCallbackInfo *info) MMModemBase *self = MM_MODEM_BASE (info->modem); MMModemBasePrivate *priv = MM_MODEM_BASE_GET_PRIVATE (self); MMModemInfoFn callback = (MMModemInfoFn) info->callback; - const char *manf, *cmanf, *model, *cmodel, *rev, *crev; + const char *manf, *cmanf, *model, *cmodel, *rev, *crev, *ati, *ati1, *gsn, *cgsn; manf = mm_callback_info_get_data (info, "card-info-manf"); cmanf = mm_callback_info_get_data (info, "card-info-c-manf"); @@ -415,6 +420,32 @@ card_info_cache_invoke (MMCallbackInfo *info) g_free (priv->revision); priv->revision = g_strdup (crev ? crev : rev); + ati = mm_callback_info_get_data (info, "card-info-ati"); + g_free (priv->ati); + priv->ati = g_strdup (ati); + + ati1 = mm_callback_info_get_data (info, "card-info-ati1"); + g_free (priv->ati1); + priv->ati1 = g_strdup (ati1); + + gsn = mm_callback_info_get_data (info, "card-info-gsn"); + cgsn = mm_callback_info_get_data (info, "card-info-c-gsn"); + g_free (priv->gsn); + priv->gsn = g_strdup (cgsn ? cgsn : gsn); + + /* Build up the device identifier */ + g_free (priv->device_ident); + priv->device_ident = mm_create_device_identifier (NULL, + NULL, + priv->ati, + priv->ati1, + priv->gsn, + priv->revision, + priv->model, + priv->manf, + mm_options_debug ()); + g_object_notify (G_OBJECT (self), MM_MODEM_DEVICE_IDENTIFIER); + callback (info->modem, priv->manf, priv->model, priv->revision, info->error, info->user_data); } @@ -425,10 +456,11 @@ info_item_done (MMCallbackInfo *info, const char *tag, const char *desc) { - const char *p; + const char *p = response->str; if (!error) { - p = mm_strip_tag (response->str, tag); + if (tag) + p = mm_strip_tag (response->str, tag); mm_callback_info_set_data (info, desc, strlen (p) ? g_strdup (p) : NULL, g_free); } @@ -453,6 +485,11 @@ GET_INFO_RESP_FN(get_c_revision_done, "+CGMR:", "card-info-c-revision") GET_INFO_RESP_FN(get_c_model_done, "+CGMM:", "card-info-c-model") GET_INFO_RESP_FN(get_c_manf_done, "+CGMI:", "card-info-c-manf") +GET_INFO_RESP_FN(get_ati_done, NULL, "card-info-ati") +GET_INFO_RESP_FN(get_ati1_done, NULL, "card-info-ati1") +GET_INFO_RESP_FN(get_gsn_done, "+GSN:", "card-info-gsn") +GET_INFO_RESP_FN(get_cgsn_done, "+CGSN:", "card-info-c-gsn") + void mm_modem_base_get_card_info (MMModemBase *self, MMAtSerialPort *port, @@ -462,7 +499,6 @@ mm_modem_base_get_card_info (MMModemBase *self, { MMModemBasePrivate *priv; MMCallbackInfo *info; - MMModemState state; gboolean cached = FALSE; GError *error = port_error; @@ -479,16 +515,8 @@ mm_modem_base_get_card_info (MMModemBase *self, */ if (priv->manf || priv->model || priv->revision) cached = TRUE; - else { - state = mm_modem_get_state (MM_MODEM (self)); - - if (port_error) - error = g_error_copy (port_error); - else if (state < MM_MODEM_STATE_ENABLING) { - error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, - "The modem is not enabled."); - } - } + else if (port_error) + error = g_error_copy (port_error); /* If we have cached info or an error, don't hit up the card */ if (cached || error) { @@ -507,13 +535,19 @@ mm_modem_base_get_card_info (MMModemBase *self, G_CALLBACK (callback), user_data); - mm_callback_info_chain_start (info, 6); + mm_callback_info_chain_start (info, 10); + mm_at_serial_port_queue_command_cached (port, "+GMI", 3, get_manf_done, info); mm_at_serial_port_queue_command_cached (port, "+GMM", 3, get_model_done, info); mm_at_serial_port_queue_command_cached (port, "+GMR", 3, get_revision_done, info); mm_at_serial_port_queue_command_cached (port, "+CGMI", 3, get_c_manf_done, info); mm_at_serial_port_queue_command_cached (port, "+CGMM", 3, get_c_model_done, info); mm_at_serial_port_queue_command_cached (port, "+CGMR", 3, get_c_revision_done, info); + + mm_at_serial_port_queue_command_cached (port, "I", 3, get_ati_done, info); + mm_at_serial_port_queue_command_cached (port, "I1", 3, get_ati1_done, info); + mm_at_serial_port_queue_command_cached (port, "+GSN", 3, get_gsn_done, info); + mm_at_serial_port_queue_command_cached (port, "+CGSN", 3, get_cgsn_done, info); } /*****************************************************************************/ @@ -574,6 +608,10 @@ mm_modem_base_init (MMModemBase *self) NULL, MM_MODEM_DBUS_INTERFACE); mm_properties_changed_signal_register_property (G_OBJECT (self), + MM_MODEM_DEVICE_IDENTIFIER, + NULL, + MM_MODEM_DBUS_INTERFACE); + mm_properties_changed_signal_register_property (G_OBJECT (self), MM_MODEM_UNLOCK_REQUIRED, NULL, MM_MODEM_DBUS_INTERFACE); @@ -630,6 +668,7 @@ set_property (GObject *object, guint prop_id, case MM_MODEM_PROP_TYPE: case MM_MODEM_PROP_ENABLED: case MM_MODEM_PROP_EQUIPMENT_IDENTIFIER: + case MM_MODEM_PROP_DEVICE_IDENTIFIER: case MM_MODEM_PROP_UNLOCK_REQUIRED: case MM_MODEM_PROP_UNLOCK_RETRIES: break; @@ -676,6 +715,9 @@ get_property (GObject *object, guint prop_id, case MM_MODEM_PROP_EQUIPMENT_IDENTIFIER: g_value_set_string (value, priv->equipment_ident); break; + case MM_MODEM_PROP_DEVICE_IDENTIFIER: + g_value_set_string (value, priv->device_ident); + break; case MM_MODEM_PROP_UNLOCK_REQUIRED: g_value_set_string (value, priv->unlock_required); break; @@ -701,7 +743,14 @@ finalize (GObject *object) g_free (priv->plugin); g_free (priv->device); g_free (priv->equipment_ident); + g_free (priv->device_ident); g_free (priv->unlock_required); + g_free (priv->manf); + g_free (priv->model); + g_free (priv->revision); + g_free (priv->ati); + g_free (priv->ati1); + g_free (priv->gsn); G_OBJECT_CLASS (mm_modem_base_parent_class)->finalize (object); } @@ -759,6 +808,10 @@ mm_modem_base_class_init (MMModemBaseClass *klass) MM_MODEM_EQUIPMENT_IDENTIFIER); g_object_class_override_property (object_class, + MM_MODEM_PROP_DEVICE_IDENTIFIER, + MM_MODEM_DEVICE_IDENTIFIER); + + g_object_class_override_property (object_class, MM_MODEM_PROP_UNLOCK_REQUIRED, MM_MODEM_UNLOCK_REQUIRED); diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index 6e76f461..11950da1 100644 --- a/src/mm-modem-helpers.c +++ b/src/mm-modem-helpers.c @@ -15,6 +15,7 @@ */ #include <config.h> +#include <ctype.h> #include <glib.h> #include <string.h> #include <ctype.h> @@ -803,3 +804,67 @@ mm_gsm_string_to_access_tech (const char *string) return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; } +/*************************************************************************/ + +char * +mm_create_device_identifier (const char *vid, + const char *pid, + const char *ati, + const char *ati1, + const char *gsn, + const char *revision, + const char *model, + const char *manf, + gboolean debug) +{ + GString *devid; + GChecksum *sum; + char *p, *ret = NULL, *j = NULL, *dbg = NULL; + + /* Build up the device identifier */ + devid = g_string_sized_new (50); + if (ati) + g_string_append (devid, ati); + if (ati1) { + /* Only append "ATI1" if it's differnet than "ATI" */ + if (!ati || (strcmp (ati, ati1) != 0)) + g_string_append (devid, ati1); + } + if (gsn) + g_string_append (devid, gsn); + if (revision) + g_string_append (devid, revision); + if (model) + g_string_append (devid, model); + if (manf) + g_string_append (devid, manf); + + if (!strlen (devid->str)) + return NULL; + + p = devid->str; + if (debug) + j = dbg = g_malloc0 (strlen (devid->str) + 1); + + sum = g_checksum_new (G_CHECKSUM_SHA1); + while (*p) { + /* Strip spaces and linebreaks */ + if (!isblank (*p) && !isspace (*p) && isascii (*p)) { + g_checksum_update (sum, (const guchar *) p, 1); + if (dbg) + *j++ = *p; + } + p++; + } + ret = g_strdup (g_checksum_get_string (sum)); + g_checksum_free (sum); + + if (dbg) { + g_debug ("Device ID source '%s'", dbg); + g_debug ("Device ID '%s'", ret); + g_free (dbg); + } + + return ret; +} + diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h index fb100bce..03f6dec2 100644 --- a/src/mm-modem-helpers.h +++ b/src/mm-modem-helpers.h @@ -59,5 +59,15 @@ gboolean mm_gsm_parse_cscs_support_response (const char *reply, MMModemGsmAccessTech mm_gsm_string_to_access_tech (const char *string); +char *mm_create_device_identifier (const char *vid, + const char *pid, + const char *ati, + const char *ati1, + const char *gsn, + const char *revision, + const char *model, + const char *manf, + gboolean debug); + #endif /* MM_MODEM_HELPERS_H */ diff --git a/src/mm-modem.c b/src/mm-modem.c index 221c9eab..30605a28 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -870,6 +870,14 @@ mm_modem_init (gpointer g_iface) g_object_interface_install_property (g_iface, + g_param_spec_string (MM_MODEM_DEVICE_IDENTIFIER, + "DeviceIdentifier", + "A best-effort identifer of the device", + NULL, + G_PARAM_READABLE)); + + g_object_interface_install_property + (g_iface, g_param_spec_string (MM_MODEM_UNLOCK_REQUIRED, "UnlockRequired", "Whether or not the modem requires an unlock " diff --git a/src/mm-modem.h b/src/mm-modem.h index 0915180b..bff7e359 100644 --- a/src/mm-modem.h +++ b/src/mm-modem.h @@ -59,6 +59,7 @@ typedef enum { #define MM_MODEM_IP_METHOD "ip-method" #define MM_MODEM_ENABLED "enabled" #define MM_MODEM_EQUIPMENT_IDENTIFIER "equipment-identifier" +#define MM_MODEM_DEVICE_IDENTIFIER "device-identifier" #define MM_MODEM_UNLOCK_REQUIRED "unlock-required" #define MM_MODEM_UNLOCK_RETRIES "unlock-retries" #define MM_MODEM_VALID "valid" /* not exported */ @@ -87,7 +88,8 @@ typedef enum { MM_MODEM_PROP_ENABLED, MM_MODEM_PROP_EQUIPMENT_IDENTIFIER, MM_MODEM_PROP_UNLOCK_REQUIRED, - MM_MODEM_PROP_UNLOCK_RETRIES + MM_MODEM_PROP_UNLOCK_RETRIES, + MM_MODEM_PROP_DEVICE_IDENTIFIER } MMModemProp; typedef struct _MMModem MMModem; diff --git a/test/info.py b/test/info.py index ee8cc5a3..347f8fe8 100755 --- a/test/info.py +++ b/test/info.py @@ -232,6 +232,7 @@ elif mtype == 2: print "Driver: '%s'" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'Driver')) print "Modem device: '%s'" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'MasterDevice')) print "Data device: '%s'" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'Device')) +print "Device ID: '%s'" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'DeviceIdentifier')) print "" modem = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM) |