PageRenderTime 112ms CodeModel.GetById 8ms app.highlight 85ms RepoModel.GetById 1ms app.codeStats 2ms

/src/mm-broadband-modem-qmi.c

https://bitbucket.org/accelecon/modemmanager
C | 7658 lines | 6171 code | 1080 blank | 407 comment | 636 complexity | 5f40a7f99878fcded4c8cbb7d20245ec MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
   2/*
   3 * This program is free software; you can redistribute it and/or modify
   4 * it under the terms of the GNU General Public License as published by
   5 * the Free Software Foundation; either version 2 of the License, or
   6 * (at your option) any later version.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details:
  12 *
  13 * Copyright (C) 2012 Google Inc.
  14 */
  15
  16#include <config.h>
  17
  18#include <stdlib.h>
  19#include <stdio.h>
  20#include <string.h>
  21#include <unistd.h>
  22#include <ctype.h>
  23
  24#include "mm-broadband-modem-qmi.h"
  25
  26#include "ModemManager.h"
  27#include "mm-log.h"
  28#include "mm-errors-types.h"
  29#include "mm-modem-helpers.h"
  30#include "mm-modem-helpers-qmi.h"
  31#include "mm-iface-modem.h"
  32#include "mm-iface-modem-3gpp.h"
  33#include "mm-iface-modem-3gpp-ussd.h"
  34#include "mm-iface-modem-cdma.h"
  35#include "mm-iface-modem-messaging.h"
  36#include "mm-iface-modem-location.h"
  37#include "mm-iface-modem-firmware.h"
  38#include "mm-sim-qmi.h"
  39#include "mm-bearer-qmi.h"
  40#include "mm-sms-qmi.h"
  41
  42static void iface_modem_init (MMIfaceModem *iface);
  43static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
  44static void iface_modem_3gpp_ussd_init (MMIfaceModem3gppUssd *iface);
  45static void iface_modem_cdma_init (MMIfaceModemCdma *iface);
  46static void iface_modem_messaging_init (MMIfaceModemMessaging *iface);
  47static void iface_modem_location_init (MMIfaceModemLocation *iface);
  48static void iface_modem_firmware_init (MMIfaceModemFirmware *iface);
  49
  50static MMIfaceModemLocation *iface_modem_location_parent;
  51
  52G_DEFINE_TYPE_EXTENDED (MMBroadbandModemQmi, mm_broadband_modem_qmi, MM_TYPE_BROADBAND_MODEM, 0,
  53                        G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
  54                        G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
  55                        G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP_USSD, iface_modem_3gpp_ussd_init)
  56                        G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_CDMA, iface_modem_cdma_init)
  57                        G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init)
  58                        G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
  59                        G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_FIRMWARE, iface_modem_firmware_init))
  60
  61struct _MMBroadbandModemQmiPrivate {
  62    /* Cached device IDs, retrieved by the modem interface when loading device
  63     * IDs, and used afterwards in the 3GPP and CDMA interfaces. */
  64    gchar *imei;
  65    gchar *meid;
  66    gchar *esn;
  67
  68    /* Cached supported frequency bands; in order to handle ANY */
  69    GArray *supported_bands;
  70
  71    /* 3GPP and CDMA share unsolicited events setup/enable/disable/cleanup */
  72    gboolean unsolicited_events_enabled;
  73    gboolean unsolicited_events_setup;
  74    guint event_report_indication_id;
  75#if defined WITH_NEWEST_QMI_COMMANDS
  76    guint signal_info_indication_id;
  77#endif /* WITH_NEWEST_QMI_COMMANDS */
  78
  79    /* 3GPP/CDMA registration helpers */
  80    gchar *current_operator_id;
  81    gchar *current_operator_description;
  82    gboolean unsolicited_registration_events_enabled;
  83    gboolean unsolicited_registration_events_setup;
  84    guint serving_system_indication_id;
  85#if defined WITH_NEWEST_QMI_COMMANDS
  86    guint system_info_indication_id;
  87#endif /* WITH_NEWEST_QMI_COMMANDS */
  88
  89    /* Messaging helpers */
  90    gboolean messaging_unsolicited_events_enabled;
  91    gboolean messaging_unsolicited_events_setup;
  92    guint messaging_event_report_indication_id;
  93
  94    /* Location helpers */
  95    MMModemLocationSource enabled_sources;
  96    guint location_event_report_indication_id;
  97
  98    /* Firmware helpers */
  99    GList *firmware_list;
 100    MMFirmwareProperties *current_firmware;
 101};
 102
 103/*****************************************************************************/
 104
 105static QmiClient *
 106peek_qmi_client (MMBroadbandModemQmi *self,
 107                 QmiService service,
 108                 GError **error)
 109{
 110    MMQmiPort *port;
 111    QmiClient *client;
 112
 113    port = mm_base_modem_peek_port_qmi (MM_BASE_MODEM (self));
 114    if (!port) {
 115        g_set_error (error,
 116                     MM_CORE_ERROR,
 117                     MM_CORE_ERROR_FAILED,
 118                     "Couldn't peek QMI port");
 119        return NULL;
 120    }
 121
 122    client = mm_qmi_port_peek_client (port,
 123                                      service,
 124                                      MM_QMI_PORT_FLAG_DEFAULT);
 125    if (!client)
 126        g_set_error (error,
 127                     MM_CORE_ERROR,
 128                     MM_CORE_ERROR_FAILED,
 129                     "Couldn't peek client for service '%s'",
 130                     qmi_service_get_string (service));
 131
 132    return client;
 133}
 134
 135static gboolean
 136ensure_qmi_client (MMBroadbandModemQmi *self,
 137                   QmiService service,
 138                   QmiClient **o_client,
 139                   GAsyncReadyCallback callback,
 140                   gpointer user_data)
 141{
 142    GError *error = NULL;
 143    QmiClient *client;
 144
 145    client = peek_qmi_client (self, service, &error);
 146    if (!client) {
 147        g_simple_async_report_take_gerror_in_idle (
 148            G_OBJECT (self),
 149            callback,
 150            user_data,
 151            error);
 152        return FALSE;
 153    }
 154
 155    *o_client = client;
 156    return TRUE;
 157}
 158
 159/*****************************************************************************/
 160/* Create Bearer (Modem interface) */
 161
 162static MMBearer *
 163modem_create_bearer_finish (MMIfaceModem *self,
 164                            GAsyncResult *res,
 165                            GError **error)
 166{
 167    MMBearer *bearer;
 168
 169    bearer = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
 170    mm_dbg ("New bearer created at DBus path '%s'", mm_bearer_get_path (bearer));
 171
 172    return g_object_ref (bearer);
 173}
 174
 175static void
 176modem_create_bearer (MMIfaceModem *self,
 177                     MMBearerProperties *properties,
 178                     GAsyncReadyCallback callback,
 179                     gpointer user_data)
 180{
 181    MMBearer *bearer;
 182    GSimpleAsyncResult *result;
 183
 184    /* Set a new ref to the bearer object as result */
 185    result = g_simple_async_result_new (G_OBJECT (self),
 186                                        callback,
 187                                        user_data,
 188                                        modem_create_bearer);
 189
 190    /* We just create a MMBearerQmi */
 191    mm_dbg ("Creating QMI bearer in QMI modem");
 192    bearer = mm_bearer_qmi_new (MM_BROADBAND_MODEM_QMI (self),
 193                                properties);
 194
 195    g_simple_async_result_set_op_res_gpointer (result, bearer, g_object_unref);
 196    g_simple_async_result_complete_in_idle (result);
 197    g_object_unref (result);
 198}
 199
 200/*****************************************************************************/
 201/* Current Capabilities loading (Modem interface) */
 202
 203typedef struct {
 204    MMBroadbandModemQmi *self;
 205    QmiClientNas *nas_client;
 206    QmiClientDms *dms_client;
 207    GSimpleAsyncResult *result;
 208    gboolean run_get_system_selection_preference;
 209    gboolean run_get_technology_preference;
 210    gboolean run_get_capabilities;
 211    MMModemCapability capabilities;
 212} LoadCurrentCapabilitiesContext;
 213
 214static MMModemCapability
 215modem_load_current_capabilities_finish (MMIfaceModem *self,
 216                                        GAsyncResult *res,
 217                                        GError **error)
 218{
 219    MMModemCapability caps;
 220    gchar *caps_str;
 221
 222    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
 223        return MM_MODEM_CAPABILITY_NONE;
 224
 225    caps = ((MMModemCapability) GPOINTER_TO_UINT (
 226                g_simple_async_result_get_op_res_gpointer (
 227                    G_SIMPLE_ASYNC_RESULT (res))));
 228    caps_str = mm_modem_capability_build_string_from_mask (caps);
 229    mm_dbg ("loaded current capabilities: %s", caps_str);
 230    g_free (caps_str);
 231    return caps;
 232}
 233
 234static void
 235load_current_capabilities_context_complete_and_free (LoadCurrentCapabilitiesContext *ctx)
 236{
 237    g_simple_async_result_complete_in_idle (ctx->result);
 238    g_object_unref (ctx->result);
 239    g_object_unref (ctx->nas_client);
 240    g_object_unref (ctx->dms_client);
 241    g_object_unref (ctx->self);
 242    g_free (ctx);
 243}
 244
 245static void load_current_capabilities_context_step (LoadCurrentCapabilitiesContext *ctx);
 246
 247static void
 248load_current_capabilities_get_capabilities_ready (QmiClientDms *client,
 249                                                  GAsyncResult *res,
 250                                                  LoadCurrentCapabilitiesContext *ctx)
 251{
 252    QmiMessageDmsGetCapabilitiesOutput *output = NULL;
 253    GError *error = NULL;
 254
 255    output = qmi_client_dms_get_capabilities_finish (client, res, &error);
 256    if (!output) {
 257        g_prefix_error (&error, "QMI operation failed: ");
 258        g_simple_async_result_take_error (ctx->result, error);
 259    } else if (!qmi_message_dms_get_capabilities_output_get_result (output, &error)) {
 260        g_prefix_error (&error, "Couldn't get Capabilities: ");
 261        g_simple_async_result_take_error (ctx->result, error);
 262    } else {
 263        guint i;
 264        guint mask = MM_MODEM_CAPABILITY_NONE;
 265        GArray *radio_interface_list;
 266
 267        qmi_message_dms_get_capabilities_output_get_info (
 268            output,
 269            NULL, /* info_max_tx_channel_rate */
 270            NULL, /* info_max_rx_channel_rate */
 271            NULL, /* info_data_service_capability */
 272            NULL, /* info_sim_capability */
 273            &radio_interface_list,
 274            NULL);
 275
 276        for (i = 0; i < radio_interface_list->len; i++) {
 277            mask |= mm_modem_capability_from_qmi_radio_interface (g_array_index (radio_interface_list,
 278                                                                                 QmiDmsRadioInterface,
 279                                                                                 i));
 280        }
 281
 282        /* Final capabilities are the intersection between the Technology
 283         * Preference (ie, allowed modes) or SSP and the device's capabilities.
 284         * If the Technology Preference was "auto" or unknown we just fall back
 285         * to the Get Capabilities response.
 286         */
 287        if (ctx->capabilities == MM_MODEM_CAPABILITY_NONE)
 288            ctx->capabilities = mask;
 289        else
 290            ctx->capabilities &= mask;
 291    }
 292
 293    if (output)
 294        qmi_message_dms_get_capabilities_output_unref (output);
 295
 296    g_simple_async_result_set_op_res_gpointer (ctx->result, GUINT_TO_POINTER (ctx->capabilities), NULL);
 297    load_current_capabilities_context_complete_and_free (ctx);
 298}
 299
 300static void
 301load_current_capabilities_get_technology_preference_ready (QmiClientNas *client,
 302                                                           GAsyncResult *res,
 303                                                           LoadCurrentCapabilitiesContext *ctx)
 304{
 305    QmiMessageNasGetTechnologyPreferenceOutput *output = NULL;
 306    GError *error = NULL;
 307
 308    output = qmi_client_nas_get_technology_preference_finish (client, res, &error);
 309    if (!output) {
 310        mm_dbg ("QMI operation failed: %s", error->message);
 311        g_error_free (error);
 312    } else if (!qmi_message_nas_get_technology_preference_output_get_result (output, &error)) {
 313        mm_dbg ("Couldn't get technology preference: %s", error->message);
 314        g_error_free (error);
 315    } else {
 316        QmiNasRadioTechnologyPreference preference_mask;
 317
 318        qmi_message_nas_get_technology_preference_output_get_active (
 319            output,
 320            &preference_mask,
 321            NULL, /* duration */
 322            NULL);
 323        if (preference_mask != QMI_NAS_RADIO_TECHNOLOGY_PREFERENCE_AUTO) {
 324            gchar *str;
 325
 326            str = qmi_nas_radio_technology_preference_build_string_from_mask (preference_mask);
 327            ctx->capabilities = mm_modem_capability_from_qmi_radio_technology_preference (preference_mask);
 328            mm_dbg ("%s modes reported in technology preference: '%s'",
 329                    ctx->capabilities == MM_MODEM_CAPABILITY_NONE ? "Unsupported" : "Valid",
 330                    str);
 331            g_free (str);
 332        }
 333    }
 334
 335    if (output)
 336        qmi_message_nas_get_technology_preference_output_unref (output);
 337
 338    /* Mark as TP already run */
 339    ctx->run_get_technology_preference = FALSE;
 340
 341    /* Get DMS Capabilities too */
 342    load_current_capabilities_context_step (ctx);
 343}
 344
 345static void
 346load_current_capabilities_get_system_selection_preference_ready (QmiClientNas *client,
 347                                                                 GAsyncResult *res,
 348                                                                 LoadCurrentCapabilitiesContext *ctx)
 349{
 350    QmiMessageNasGetSystemSelectionPreferenceOutput *output = NULL;
 351    GError *error = NULL;
 352    QmiNasRatModePreference mode_preference_mask = 0;
 353
 354    output = qmi_client_nas_get_system_selection_preference_finish (client, res, &error);
 355    if (!output) {
 356        mm_dbg ("QMI operation failed: %s", error->message);
 357        g_error_free (error);
 358    } else if (!qmi_message_nas_get_system_selection_preference_output_get_result (output, &error)) {
 359        mm_dbg ("Couldn't get system selection preference: %s", error->message);
 360        g_error_free (error);
 361    } else if (!qmi_message_nas_get_system_selection_preference_output_get_mode_preference (
 362                   output,
 363                   &mode_preference_mask,
 364                   NULL)) {
 365        QmiNasBandPreference band_preference_mask;
 366
 367        mm_dbg ("Mode preference not reported in system selection preference");
 368
 369        if (qmi_message_nas_get_system_selection_preference_output_get_band_preference (
 370                output,
 371                &band_preference_mask,
 372                NULL)) {
 373            gchar *str;
 374
 375            str = qmi_nas_band_preference_build_string_from_mask (band_preference_mask);
 376            ctx->capabilities = mm_modem_capability_from_qmi_band_preference (band_preference_mask);
 377            mm_dbg ("%s bands reported in system selection preference: '%s'",
 378                    ctx->capabilities == MM_MODEM_CAPABILITY_NONE ? "Unsupported" : "Valid",
 379                    str);
 380            g_free (str);
 381
 382            /* Just the presence of the LTE band preference tells us it's LTE */
 383            if (qmi_message_nas_get_system_selection_preference_output_get_lte_band_preference (
 384                    output,
 385                    NULL,
 386                    NULL)) {
 387                mm_dbg ("LTE band preference found");
 388                ctx->capabilities |= MM_MODEM_CAPABILITY_LTE;
 389            }
 390        } else
 391            mm_dbg ("Band preference not reported in system selection preference");
 392    } else {
 393        gchar *str;
 394
 395        str = qmi_nas_rat_mode_preference_build_string_from_mask (mode_preference_mask);
 396        ctx->capabilities = mm_modem_capability_from_qmi_rat_mode_preference (mode_preference_mask);
 397        mm_dbg ("%s capabilities reported in system selection preference: '%s'",
 398                ctx->capabilities == MM_MODEM_CAPABILITY_NONE ? "Unsupported" : "Valid",
 399                str);
 400        g_free (str);
 401    }
 402
 403    if (output)
 404        qmi_message_nas_get_system_selection_preference_output_unref (output);
 405
 406    /* Mark as SSP already run */
 407    ctx->run_get_system_selection_preference = FALSE;
 408
 409    /* If we got some value, cache it and go on to DMS Get Capabilities */
 410    if (ctx->capabilities != MM_MODEM_CAPABILITY_NONE)
 411        ctx->run_get_technology_preference = FALSE;
 412
 413    load_current_capabilities_context_step (ctx);
 414}
 415
 416static void
 417load_current_capabilities_context_step (LoadCurrentCapabilitiesContext *ctx)
 418{
 419    if (ctx->run_get_system_selection_preference) {
 420        qmi_client_nas_get_system_selection_preference (
 421            ctx->nas_client,
 422            NULL, /* no input */
 423            5,
 424            NULL, /* cancellable */
 425            (GAsyncReadyCallback)load_current_capabilities_get_system_selection_preference_ready,
 426            ctx);
 427        return;
 428    }
 429
 430    if (ctx->run_get_technology_preference) {
 431        qmi_client_nas_get_technology_preference (
 432            ctx->nas_client,
 433            NULL, /* no input */
 434            5,
 435            NULL, /* cancellable */
 436            (GAsyncReadyCallback)load_current_capabilities_get_technology_preference_ready,
 437            ctx);
 438        return;
 439    }
 440
 441    if (ctx->run_get_capabilities) {
 442        qmi_client_dms_get_capabilities (
 443            ctx->dms_client,
 444            NULL, /* no input */
 445            5,
 446            NULL, /* cancellable */
 447            (GAsyncReadyCallback)load_current_capabilities_get_capabilities_ready,
 448            ctx);
 449        return;
 450    }
 451
 452    g_simple_async_result_set_error (
 453        ctx->result,
 454        MM_CORE_ERROR,
 455        MM_CORE_ERROR_UNSUPPORTED,
 456        "Loading current capabilities is not supported by this device");
 457    load_current_capabilities_context_complete_and_free (ctx);
 458}
 459
 460static void
 461modem_load_current_capabilities (MMIfaceModem *self,
 462                                 GAsyncReadyCallback callback,
 463                                 gpointer user_data)
 464{
 465    LoadCurrentCapabilitiesContext *ctx;
 466    QmiClient *nas_client = NULL;
 467    QmiClient *dms_client = NULL;
 468
 469    /* Best way to get current capabilities (ie, enabled radios) is
 470     * Get System Selection Preference's "mode preference" TLV, but that's
 471     * only supported by NAS >= 1.1, meaning older Gobi devices don't
 472     * implement it.
 473     *
 474     * On these devices, the DMS Get Capabilities call appears to report
 475     * currently enabled radios, but this does not take the user's
 476     * technology preference into account.
 477     *
 478     * So in the absence of System Selection Preference, we check the
 479     * Technology Preference first, and if that is "AUTO" we fall back to
 480     * Get Capabilities.
 481     */
 482
 483    mm_dbg ("loading current capabilities...");
 484
 485    if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
 486                            QMI_SERVICE_NAS, &nas_client,
 487                            callback, user_data))
 488        return;
 489
 490    if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
 491                            QMI_SERVICE_DMS, &dms_client,
 492                            callback, user_data))
 493        return;
 494
 495    ctx = g_new0 (LoadCurrentCapabilitiesContext, 1);
 496    ctx->self = g_object_ref (self);
 497    ctx->nas_client = g_object_ref (nas_client);
 498    ctx->dms_client = g_object_ref (dms_client);
 499    ctx->result = g_simple_async_result_new (G_OBJECT (self),
 500                                             callback,
 501                                             user_data,
 502                                             modem_load_current_capabilities);
 503    ctx->capabilities = MM_MODEM_CAPABILITY_NONE;
 504
 505    /* System selection preference introduced in NAS 1.1 */
 506    ctx->run_get_system_selection_preference = qmi_client_check_version (nas_client, 1, 1);
 507
 508    ctx->run_get_technology_preference = TRUE;
 509    ctx->run_get_capabilities = TRUE;
 510
 511    load_current_capabilities_context_step (ctx);
 512}
 513
 514/*****************************************************************************/
 515/* Modem Capabilities loading (Modem interface) */
 516
 517static MMModemCapability
 518modem_load_modem_capabilities_finish (MMIfaceModem *self,
 519                                      GAsyncResult *res,
 520                                      GError **error)
 521{
 522    MMModemCapability caps;
 523    gchar *caps_str;
 524
 525    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
 526        return MM_MODEM_CAPABILITY_NONE;
 527
 528    caps = ((MMModemCapability) GPOINTER_TO_UINT (
 529                g_simple_async_result_get_op_res_gpointer (
 530                    G_SIMPLE_ASYNC_RESULT (res))));
 531    caps_str = mm_modem_capability_build_string_from_mask (caps);
 532    mm_dbg ("loaded modem capabilities: %s", caps_str);
 533    g_free (caps_str);
 534    return caps;
 535}
 536
 537static void
 538dms_get_capabilities_ready (QmiClientDms *client,
 539                            GAsyncResult *res,
 540                            GSimpleAsyncResult *simple)
 541{
 542    QmiMessageDmsGetCapabilitiesOutput *output = NULL;
 543    GError *error = NULL;
 544
 545    output = qmi_client_dms_get_capabilities_finish (client, res, &error);
 546    if (!output) {
 547        g_prefix_error (&error, "QMI operation failed: ");
 548        g_simple_async_result_take_error (simple, error);
 549    } else if (!qmi_message_dms_get_capabilities_output_get_result (output, &error)) {
 550        g_prefix_error (&error, "Couldn't get modem capabilities: ");
 551        g_simple_async_result_take_error (simple, error);
 552    } else {
 553        guint i;
 554        guint mask = MM_MODEM_CAPABILITY_NONE;
 555        GArray *radio_interface_list;
 556
 557        qmi_message_dms_get_capabilities_output_get_info (
 558            output,
 559            NULL, /* info_max_tx_channel_rate */
 560            NULL, /* info_max_rx_channel_rate */
 561            NULL, /* info_data_service_capability */
 562            NULL, /* info_sim_capability */
 563            &radio_interface_list,
 564            NULL);
 565
 566        for (i = 0; i < radio_interface_list->len; i++) {
 567            mask |= mm_modem_capability_from_qmi_radio_interface (g_array_index (radio_interface_list,
 568                                                                                 QmiDmsRadioInterface,
 569                                                                                 i));
 570        }
 571
 572        g_simple_async_result_set_op_res_gpointer (simple,
 573                                                   GUINT_TO_POINTER (mask),
 574                                                   NULL);
 575    }
 576
 577    if (output)
 578        qmi_message_dms_get_capabilities_output_unref (output);
 579
 580    g_simple_async_result_complete (simple);
 581    g_object_unref (simple);
 582}
 583
 584static void
 585modem_load_modem_capabilities (MMIfaceModem *self,
 586                               GAsyncReadyCallback callback,
 587                               gpointer user_data)
 588{
 589    GSimpleAsyncResult *result;
 590    QmiClient *client = NULL;
 591
 592    if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
 593                            QMI_SERVICE_DMS, &client,
 594                            callback, user_data))
 595        return;
 596
 597    result = g_simple_async_result_new (G_OBJECT (self),
 598                                        callback,
 599                                        user_data,
 600                                        modem_load_modem_capabilities);
 601
 602    mm_dbg ("loading modem capabilities...");
 603    qmi_client_dms_get_capabilities (QMI_CLIENT_DMS (client),
 604                                     NULL,
 605                                     5,
 606                                     NULL,
 607                                     (GAsyncReadyCallback)dms_get_capabilities_ready,
 608                                     result);
 609}
 610
 611/*****************************************************************************/
 612/* Manufacturer loading (Modem interface) */
 613
 614static gchar *
 615modem_load_manufacturer_finish (MMIfaceModem *self,
 616                                GAsyncResult *res,
 617                                GError **error)
 618{
 619    gchar *manufacturer;
 620
 621    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
 622        return NULL;
 623
 624    manufacturer = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
 625    mm_dbg ("loaded manufacturer: %s", manufacturer);
 626    return manufacturer;
 627}
 628
 629static void
 630dms_get_manufacturer_ready (QmiClientDms *client,
 631                            GAsyncResult *res,
 632                            GSimpleAsyncResult *simple)
 633{
 634    QmiMessageDmsGetManufacturerOutput *output = NULL;
 635    GError *error = NULL;
 636
 637    output = qmi_client_dms_get_manufacturer_finish (client, res, &error);
 638    if (!output) {
 639        g_prefix_error (&error, "QMI operation failed: ");
 640        g_simple_async_result_take_error (simple, error);
 641    } else if (!qmi_message_dms_get_manufacturer_output_get_result (output, &error)) {
 642        g_prefix_error (&error, "Couldn't get Manufacturer: ");
 643        g_simple_async_result_take_error (simple, error);
 644    } else {
 645        const gchar *str;
 646
 647        qmi_message_dms_get_manufacturer_output_get_manufacturer (output, &str, NULL);
 648        g_simple_async_result_set_op_res_gpointer (simple,
 649                                                   g_strdup (str),
 650                                                   (GDestroyNotify)g_free);
 651    }
 652
 653    if (output)
 654        qmi_message_dms_get_manufacturer_output_unref (output);
 655
 656    g_simple_async_result_complete (simple);
 657    g_object_unref (simple);
 658}
 659
 660static void
 661modem_load_manufacturer (MMIfaceModem *self,
 662                         GAsyncReadyCallback callback,
 663                         gpointer user_data)
 664{
 665    GSimpleAsyncResult *result;
 666    QmiClient *client = NULL;
 667
 668    if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
 669                            QMI_SERVICE_DMS, &client,
 670                            callback, user_data))
 671        return;
 672
 673    result = g_simple_async_result_new (G_OBJECT (self),
 674                                        callback,
 675                                        user_data,
 676                                        modem_load_manufacturer);
 677
 678    mm_dbg ("loading manufacturer...");
 679    qmi_client_dms_get_manufacturer (QMI_CLIENT_DMS (client),
 680                                     NULL,
 681                                     5,
 682                                     NULL,
 683                                     (GAsyncReadyCallback)dms_get_manufacturer_ready,
 684                                     result);
 685}
 686
 687/*****************************************************************************/
 688/* Model loading (Modem interface) */
 689
 690static gchar *
 691modem_load_model_finish (MMIfaceModem *self,
 692                         GAsyncResult *res,
 693                         GError **error)
 694{
 695    gchar *model;
 696
 697    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
 698        return NULL;
 699
 700    model = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
 701    mm_dbg ("loaded model: %s", model);
 702    return model;
 703}
 704
 705static void
 706dms_get_model_ready (QmiClientDms *client,
 707                     GAsyncResult *res,
 708                     GSimpleAsyncResult *simple)
 709{
 710    QmiMessageDmsGetModelOutput *output = NULL;
 711    GError *error = NULL;
 712
 713    output = qmi_client_dms_get_model_finish (client, res, &error);
 714    if (!output) {
 715        g_prefix_error (&error, "QMI operation failed: ");
 716        g_simple_async_result_take_error (simple, error);
 717    } else if (!qmi_message_dms_get_model_output_get_result (output, &error)) {
 718        g_prefix_error (&error, "Couldn't get Model: ");
 719        g_simple_async_result_take_error (simple, error);
 720    } else {
 721        const gchar *str;
 722
 723        qmi_message_dms_get_model_output_get_model (output, &str, NULL);
 724        g_simple_async_result_set_op_res_gpointer (simple,
 725                                                   g_strdup (str),
 726                                                   (GDestroyNotify)g_free);
 727    }
 728
 729    if (output)
 730        qmi_message_dms_get_model_output_unref (output);
 731
 732    g_simple_async_result_complete (simple);
 733    g_object_unref (simple);
 734}
 735
 736static void
 737modem_load_model (MMIfaceModem *self,
 738                  GAsyncReadyCallback callback,
 739                  gpointer user_data)
 740{
 741    GSimpleAsyncResult *result;
 742    QmiClient *client = NULL;
 743
 744    if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
 745                            QMI_SERVICE_DMS, &client,
 746                            callback, user_data))
 747        return;
 748
 749    result = g_simple_async_result_new (G_OBJECT (self),
 750                                        callback,
 751                                        user_data,
 752                                        modem_load_model);
 753
 754    mm_dbg ("loading model...");
 755    qmi_client_dms_get_model (QMI_CLIENT_DMS (client),
 756                              NULL,
 757                              5,
 758                              NULL,
 759                              (GAsyncReadyCallback)dms_get_model_ready,
 760                              result);
 761}
 762
 763/*****************************************************************************/
 764/* Revision loading (Modem interface) */
 765
 766static gchar *
 767modem_load_revision_finish (MMIfaceModem *self,
 768                            GAsyncResult *res,
 769                            GError **error)
 770{
 771    gchar *revision;
 772
 773    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
 774        return NULL;
 775
 776    revision = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
 777    mm_dbg ("loaded revision: %s", revision);
 778    return revision;
 779}
 780
 781static void
 782dms_get_revision_ready (QmiClientDms *client,
 783                        GAsyncResult *res,
 784                        GSimpleAsyncResult *simple)
 785{
 786    QmiMessageDmsGetRevisionOutput *output = NULL;
 787    GError *error = NULL;
 788
 789    output = qmi_client_dms_get_revision_finish (client, res, &error);
 790    if (!output) {
 791        g_prefix_error (&error, "QMI operation failed: ");
 792        g_simple_async_result_take_error (simple, error);
 793    } else if (!qmi_message_dms_get_revision_output_get_result (output, &error)) {
 794        g_prefix_error (&error, "Couldn't get Revision: ");
 795        g_simple_async_result_take_error (simple, error);
 796    } else {
 797        const gchar *str;
 798
 799        qmi_message_dms_get_revision_output_get_revision (output, &str, NULL);
 800        g_simple_async_result_set_op_res_gpointer (simple,
 801                                                   g_strdup (str),
 802                                                   (GDestroyNotify)g_free);
 803    }
 804
 805    if (output)
 806        qmi_message_dms_get_revision_output_unref (output);
 807
 808    g_simple_async_result_complete (simple);
 809    g_object_unref (simple);
 810}
 811
 812static void
 813modem_load_revision (MMIfaceModem *self,
 814                     GAsyncReadyCallback callback,
 815                     gpointer user_data)
 816{
 817    GSimpleAsyncResult *result;
 818    QmiClient *client = NULL;
 819
 820    if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
 821                            QMI_SERVICE_DMS, &client,
 822                            callback, user_data))
 823        return;
 824
 825    result = g_simple_async_result_new (G_OBJECT (self),
 826                                        callback,
 827                                        user_data,
 828                                        modem_load_revision);
 829
 830    mm_dbg ("loading revision...");
 831    qmi_client_dms_get_revision (QMI_CLIENT_DMS (client),
 832                                 NULL,
 833                                 5,
 834                                 NULL,
 835                                 (GAsyncReadyCallback)dms_get_revision_ready,
 836                                 result);
 837}
 838
 839/*****************************************************************************/
 840/* Equipment Identifier loading (Modem interface) */
 841
 842typedef struct {
 843    MMBroadbandModemQmi *self;
 844    QmiClient *client;
 845    GSimpleAsyncResult *result;
 846} LoadEquipmentIdentifierContext;
 847
 848static void
 849load_equipment_identifier_context_complete_and_free (LoadEquipmentIdentifierContext *ctx)
 850{
 851    g_simple_async_result_complete (ctx->result);
 852    g_object_unref (ctx->result);
 853    g_object_unref (ctx->client);
 854    g_object_unref (ctx->self);
 855    g_free (ctx);
 856}
 857
 858static gchar *
 859modem_load_equipment_identifier_finish (MMIfaceModem *self,
 860                                        GAsyncResult *res,
 861                                        GError **error)
 862{
 863    gchar *equipment_identifier;
 864
 865    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
 866        return NULL;
 867
 868    equipment_identifier = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
 869    mm_dbg ("loaded equipment identifier: %s", equipment_identifier);
 870    return equipment_identifier;
 871}
 872
 873static void
 874dms_get_ids_ready (QmiClientDms *client,
 875                   GAsyncResult *res,
 876                   LoadEquipmentIdentifierContext *ctx)
 877{
 878    QmiMessageDmsGetIdsOutput *output = NULL;
 879    GError *error = NULL;
 880    const gchar *str;
 881
 882    output = qmi_client_dms_get_ids_finish (client, res, &error);
 883    if (!output) {
 884        g_prefix_error (&error, "QMI operation failed: ");
 885        g_simple_async_result_take_error (ctx->result, error);
 886        load_equipment_identifier_context_complete_and_free (ctx);
 887        return;
 888    }
 889
 890    if (!qmi_message_dms_get_ids_output_get_result (output, &error)) {
 891        g_prefix_error (&error, "Couldn't get IDs: ");
 892        g_simple_async_result_take_error (ctx->result, error);
 893        qmi_message_dms_get_ids_output_unref (output);
 894        load_equipment_identifier_context_complete_and_free (ctx);
 895        return;
 896    }
 897
 898    /* In order:
 899     * If we have a IMEI, use it...
 900     * Otherwise, if we have a ESN, use it...
 901     * Otherwise, if we have a MEID, use it...
 902     * Otherwise, 'unknown'
 903     */
 904
 905    if (qmi_message_dms_get_ids_output_get_imei (output, &str, NULL) &&
 906        str[0] != '\0' && str[0] != '0') {
 907        g_free (ctx->self->priv->imei);
 908        ctx->self->priv->imei = g_strdup (str);
 909    }
 910
 911    if (qmi_message_dms_get_ids_output_get_esn (output, &str, NULL) &&
 912        str[0] != '\0' && str[0] != '0') {
 913        g_free (ctx->self->priv->esn);
 914        ctx->self->priv->esn = g_strdup (str);
 915    }
 916
 917    if (qmi_message_dms_get_ids_output_get_meid (output, &str, NULL) &&
 918        str[0] != '\0' && str[0] != '0') {
 919        g_free (ctx->self->priv->meid);
 920        ctx->self->priv->meid = g_strdup (str);
 921    }
 922
 923    if (ctx->self->priv->imei)
 924        str = ctx->self->priv->imei;
 925    else if (ctx->self->priv->esn)
 926        str = ctx->self->priv->esn;
 927    else if (ctx->self->priv->meid)
 928        str = ctx->self->priv->meid;
 929    else
 930        str = "unknown";
 931
 932    g_simple_async_result_set_op_res_gpointer (ctx->result,
 933                                               g_strdup (str),
 934                                               (GDestroyNotify)g_free);
 935
 936    qmi_message_dms_get_ids_output_unref (output);
 937    load_equipment_identifier_context_complete_and_free (ctx);
 938}
 939
 940static void
 941modem_load_equipment_identifier (MMIfaceModem *self,
 942                                 GAsyncReadyCallback callback,
 943                                 gpointer user_data)
 944{
 945    LoadEquipmentIdentifierContext *ctx;
 946    QmiClient *client = NULL;
 947
 948    if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
 949                            QMI_SERVICE_DMS, &client,
 950                            callback, user_data))
 951        return;
 952
 953    ctx = g_new (LoadEquipmentIdentifierContext, 1);
 954    ctx->self = g_object_ref (self);
 955    ctx->client = g_object_ref (client);
 956    ctx->result = g_simple_async_result_new (G_OBJECT (self),
 957                                             callback,
 958                                             user_data,
 959                                             modem_load_equipment_identifier);
 960
 961    mm_dbg ("loading equipment identifier...");
 962    qmi_client_dms_get_ids (QMI_CLIENT_DMS (client),
 963                            NULL,
 964                            5,
 965                            NULL,
 966                            (GAsyncReadyCallback)dms_get_ids_ready,
 967                            ctx);
 968}
 969
 970/*****************************************************************************/
 971/* Device identifier loading (Modem interface) */
 972
 973static gchar *
 974modem_load_device_identifier_finish (MMIfaceModem *self,
 975                                     GAsyncResult *res,
 976                                     GError **error)
 977{
 978    gchar *device_identifier;
 979
 980    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
 981        return NULL;
 982
 983    device_identifier = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
 984    mm_dbg ("loaded device identifier: %s", device_identifier);
 985    return device_identifier;
 986}
 987
 988static void
 989modem_load_device_identifier (MMIfaceModem *self,
 990                              GAsyncReadyCallback callback,
 991                              gpointer user_data)
 992{
 993    GSimpleAsyncResult *result;
 994    gchar *device_identifier;
 995
 996    mm_dbg ("loading device identifier...");
 997    result = g_simple_async_result_new (G_OBJECT (self),
 998                                        callback,
 999                                        user_data,
1000                                        modem_load_device_identifier);
1001
1002    /* Just use dummy ATI/ATI1 replies, all the other internal info should be
1003     * enough for uniqueness */
1004    device_identifier = mm_broadband_modem_create_device_identifier (MM_BROADBAND_MODEM (self), "", "");
1005    g_simple_async_result_set_op_res_gpointer (result,
1006                                               device_identifier,
1007                                               (GDestroyNotify)g_free);
1008    g_simple_async_result_complete_in_idle (result);
1009    g_object_unref (result);
1010}
1011
1012/*****************************************************************************/
1013/* Own Numbers loading (Modem interface) */
1014
1015static GStrv
1016modem_load_own_numbers_finish (MMIfaceModem *self,
1017                               GAsyncResult *res,
1018                               GError **error)
1019{
1020    gchar **own_numbers;
1021
1022    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
1023        return NULL;
1024
1025    own_numbers = g_new0 (gchar *, 2);
1026    own_numbers[0] = g_strdup (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
1027    mm_dbg ("loaded own numbers: %s", own_numbers[0]);
1028    return own_numbers;
1029}
1030
1031static void
1032dms_get_msisdn_ready (QmiClientDms *client,
1033                      GAsyncResult *res,
1034                      GSimpleAsyncResult *simple)
1035{
1036    QmiMessageDmsGetMsisdnOutput *output = NULL;
1037    GError *error = NULL;
1038
1039    output = qmi_client_dms_get_msisdn_finish (client, res, &error);
1040    if (!output) {
1041        g_prefix_error (&error, "QMI operation failed: ");
1042        g_simple_async_result_take_error (simple, error);
1043    } else if (!qmi_message_dms_get_msisdn_output_get_result (output, &error)) {
1044        g_prefix_error (&error, "Couldn't get MSISDN: ");
1045        g_simple_async_result_take_error (simple, error);
1046    } else {
1047        const gchar *str = NULL;
1048
1049        qmi_message_dms_get_msisdn_output_get_msisdn (output, &str, NULL);
1050        g_simple_async_result_set_op_res_gpointer (simple,
1051                                                   g_strdup (str),
1052                                                   (GDestroyNotify)g_free);
1053    }
1054
1055    if (output)
1056        qmi_message_dms_get_msisdn_output_unref (output);
1057
1058    g_simple_async_result_complete (simple);
1059    g_object_unref (simple);
1060}
1061
1062static void
1063modem_load_own_numbers (MMIfaceModem *self,
1064                        GAsyncReadyCallback callback,
1065                        gpointer user_data)
1066{
1067    GSimpleAsyncResult *result;
1068    QmiClient *client = NULL;
1069
1070    if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
1071                            QMI_SERVICE_DMS, &client,
1072                            callback, user_data))
1073        return;
1074
1075    result = g_simple_async_result_new (G_OBJECT (self),
1076                                        callback,
1077                                        user_data,
1078                                        modem_load_own_numbers);
1079
1080    mm_dbg ("loading own numbers...");
1081    qmi_client_dms_get_msisdn (QMI_CLIENT_DMS (client),
1082                               NULL,
1083                               5,
1084                               NULL,
1085                               (GAsyncReadyCallback)dms_get_msisdn_ready,
1086                               result);
1087}
1088
1089/*****************************************************************************/
1090/* Check if unlock required (Modem interface) */
1091
1092static MMModemLock
1093modem_load_unlock_required_finish (MMIfaceModem *self,
1094                                   GAsyncResult *res,
1095                                   GError **error)
1096{
1097    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
1098        return MM_MODEM_LOCK_UNKNOWN;
1099
1100    return (MMModemLock) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
1101                                               G_SIMPLE_ASYNC_RESULT (res)));
1102}
1103
1104static void
1105dms_uim_get_pin_status_ready (QmiClientDms *client,
1106                              GAsyncResult *res,
1107                              GSimpleAsyncResult *simple)
1108{
1109    QmiMessageDmsUimGetPinStatusOutput *output;
1110    GError *error = NULL;
1111
1112    output = qmi_client_dms_uim_get_pin_status_finish (client, res, &error);
1113    if (!output) {
1114        g_prefix_error (&error, "QMI operation failed: ");
1115        g_simple_async_result_take_error (simple, error);
1116    } else if (!qmi_message_dms_uim_get_pin_status_output_get_result (output, &error)) {
1117        /* When no SIM inserted, an internal error when checking PIN status
1118         * needs to be fatal so that we mark the modem unusable. */
1119        if (g_error_matches (error,
1120                             QMI_PROTOCOL_ERROR,
1121                             QMI_PROTOCOL_ERROR_INTERNAL)) {
1122            g_simple_async_result_set_error (simple,
1123                                             MM_MOBILE_EQUIPMENT_ERROR,
1124                                             MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE,
1125                                             "Couldn't get PIN status: %s",
1126                                             error->message);
1127            g_error_free (error);
1128        } else {
1129            g_prefix_error (&error, "Couldn't get PIN status: ");
1130            g_simple_async_result_take_error (simple, error);
1131        }
1132    } else {
1133        MMModemLock lock = MM_MODEM_LOCK_UNKNOWN;
1134        QmiDmsUimPinStatus current_status;
1135
1136        if (qmi_message_dms_uim_get_pin_status_output_get_pin1_status (
1137                output,
1138                &current_status,
1139                NULL, /* verify_retries_left */
1140                NULL, /* unblock_retries_left */
1141                NULL))
1142            lock = mm_modem_lock_from_qmi_uim_pin_status (current_status, TRUE);
1143
1144        if (lock == MM_MODEM_LOCK_NONE &&
1145            qmi_message_dms_uim_get_pin_status_output_get_pin2_status (
1146                output,
1147                &current_status,
1148                NULL, /* verify_retries_left */
1149                NULL, /* unblock_retries_left */
1150                NULL))
1151            lock = mm_modem_lock_from_qmi_uim_pin_status (current_status, FALSE);
1152
1153        g_simple_async_result_set_op_res_gpointer (simple, GUINT_TO_POINTER (lock), NULL);
1154    }
1155
1156    if (output)
1157        qmi_message_dms_uim_get_pin_status_output_unref (output);
1158
1159    g_simple_async_result_complete (simple);
1160    g_object_unref (simple);
1161}
1162
1163static void
1164modem_load_unlock_required (MMIfaceModem *self,
1165                            GAsyncReadyCallback callback,
1166                            gpointer user_data)
1167{
1168    GSimpleAsyncResult *result;
1169    QmiClient *client = NULL;
1170
1171    if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
1172                            QMI_SERVICE_DMS, &client,
1173                            callback, user_data))
1174        return;
1175
1176    result = g_simple_async_result_new (G_OBJECT (self),
1177                                        callback,
1178                                        user_data,
1179                                        modem_load_unlock_required);
1180
1181    /* CDMA-only modems don't need this */
1182    if (mm_iface_modem_is_cdma_only (self)) {
1183        mm_dbg ("Skipping unlock check in CDMA-only modem...");
1184        g_simple_async_result_set_op_res_gpointer (result,
1185                                                   GUINT_TO_POINTER (MM_MODEM_LOCK_NONE),
1186                                                   NULL);
1187        g_simple_async_result_complete_in_idle (result);
1188        g_object_unref (result);
1189        return;
1190    }
1191
1192    mm_dbg ("loading unlock required...");
1193    qmi_client_dms_uim_get_pin_status (QMI_CLIENT_DMS (client),
1194                                       NULL,
1195                                       5,
1196                                       NULL,
1197                                       (GAsyncReadyCallback)dms_uim_get_pin_status_ready,
1198                                       result);
1199}
1200
1201/*****************************************************************************/
1202/* Check if unlock retries (Modem interface) */
1203
1204static MMUnlockRetries *
1205modem_load_unlock_retries_finish (MMIfaceModem *self,
1206                                  GAsyncResult *res,
1207                                  GError **error)
1208{
1209    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
1210        return NULL;
1211
1212    return MM_UNLOCK_RETRIES (g_object_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))));
1213}
1214
1215static void
1216retry_count_dms_uim_get_pin_status_ready (QmiClientDms *client,
1217                                          GAsyncResult *res,
1218                                          GSimpleAsyncResult *simple)
1219{
1220    QmiMessageDmsUimGetPinStatusOutput *output;
1221    GError *error = NULL;
1222
1223    output = qmi_client_dms_uim_get_pin_status_finish (client, res, &error);
1224    if (!output) {
1225        g_prefix_error (&error, "QMI operation failed: ");
1226        g_simple_async_result_take_error (simple, error);
1227    } else if (!qmi_message_dms_uim_get_pin_status_output_get_result (output, &error)) {
1228        g_prefix_error (&error, "Couldn't get unlock retries: ");
1229        g_simple_async_result_take_error (simple, error);
1230    } else {
1231        MMUnlockRetries *retries;
1232        guint8 verify_retries_left;
1233        guint8 unblock_retries_left;
1234
1235        retries = mm_unlock_retries_new ();
1236
1237        if (qmi_message_dms_uim_get_pin_status_output_get_pin1_status (
1238                output,
1239                NULL, /* current_status */
1240                &verify_retries_left,
1241                &unblock_retries_left,
1242                NULL)) {
1243            mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PIN, verify_retries_left);
1244            mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PUK, unblock_retries_left);
1245        }
1246
1247        if (qmi_message_dms_uim_get_pin_status_output_get_pin2_status (
1248                output,
1249                NULL, /* current_status */
1250                &verify_retries_left,
1251                &unblock_retries_left,
1252                NULL)) {
1253            mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PIN2, verify_retries_left);
1254            mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PUK2, unblock_retries_left);
1255        }
1256
1257        g_simple_async_result_set_op_res_gpointer (simple, retries, g_object_unref);
1258    }
1259
1260    if (output)
1261        qmi_message_dms_uim_get_pin_status_output_unref (output);
1262
1263    g_simple_async_result_complete (simple);
1264    g_object_unref (simple);
1265}
1266
1267static void
1268modem_load_unlock_retries (MMIfaceModem *self,
1269                           GAsyncReadyCallback callback,
1270                           gpointer user_data)
1271{
1272    GSimpleAsyncResult *result;
1273    QmiClient *client = NULL;
1274
1275    if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
1276                            QMI_SERVICE_DMS, &client,
1277                            callback, user_data))
1278        return;
1279
1280    result = g_simple_async_result_new (G_OBJECT (self),
1281                                        callback,
1282                                        user_data,
1283                                        modem_load_unlock_retries);
1284
1285    mm_dbg ("loading unlock retries...");
1286    qmi_client_dms_uim_get_pin_status (QMI_CLIENT_DMS (client),
1287                                       NULL,
1288                                       5,
1289                                       NULL,
1290                                       (GAsyncReadyCallback)retry_count_dms_uim_get_pin_status_ready,
1291                                       result);
1292}
1293
1294/*****************************************************************************/
1295/* Load supported bands (Modem interface) */
1296
1297static GArray *
1298modem_load_supported_bands_finish (MMIfaceModem *_self,
1299                                   GAsyncResult *res,
1300                                   GError **error)
1301{
1302    MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
1303
1304    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
1305        return NULL;
1306
1307    if (self->priv->supported_bands)
1308        g_array_unref (self->priv->supported_bands);
1309
1310    /* Cache the supported bands value */
1311    self->priv->supported_bands = g_array_ref (g_simple_async_result_get_op_res_gpointer (
1312                                                   G_SIMPLE_ASYNC_RESULT (res)));
1313
1314    return g_array_ref (self->priv->supported_bands);
1315}
1316
1317static void
1318dms_get_band_capabilities_ready (QmiClientDms *client,
1319                                 GAsyncResult *res,
1320                                 GSimpleAsyncResult *simple)
1321{
1322    QmiMessageDmsGetBandCapabilitiesOutput *output;
1323    GError *error = NULL;
1324
1325    output = qmi_client_dms_get_band_capabilities_finish (client, res, &error);
1326    if (!output) {
1327        g_prefix_error (&error, "QMI operation failed: ");
1328        g_simple_async_result_take_error (simple, error);
1329    } else if (!qmi_message_dms_get_band_capabilities_output_get_result (output, &error)) {
1330        g_prefix_error (&error, "Couldn't get band capabilities: ");
1331        g_simple_async_result_take_error (simple, error);
1332    } else {
1333        GArray *mm_bands;
1334        QmiDmsBandCapability qmi_bands = 0;
1335        QmiDmsLteBandCapability qmi_lte_bands = 0;
1336
1337        qmi_message_dms_get_band_capabilities_output_get_band_capability (
1338            output,
1339            &qmi_bands,
1340            NULL);
1341        qmi_message_dms_get_band_capabilities_output_get_lte_band_capability (
1342            output,
1343            &qmi_lte_bands,
1344            NULL);
1345
1346        mm_bands = mm_modem_bands_from_qmi_band_capabilities (qmi_bands, qmi_lte_bands);
1347
1348        if (mm_bands->len == 0) {
1349            g_array_unref (mm_bands);
1350            g_simple_async_result_set_error (simple,
1351                                             MM_CORE_ERROR,
1352                                             MM_CORE_ERROR

Large files files are truncated, but you can click here to view the full file