Ejemplo n.º 1
0
static MMBaseModem *
create_modem (MMPlugin *self,
              const gchar *sysfs_path,
              const gchar **drivers,
              guint16 vendor,
              guint16 product,
              GList *probes,
              GError **error)
{
    propagate_port_mode_results (probes);

#if defined WITH_QMI
    if (mm_port_probe_list_has_qmi_port (probes)) {
        mm_dbg ("QMI-powered Huawei modem found...");
        return MM_BASE_MODEM (mm_broadband_modem_qmi_new (sysfs_path,
                                                          drivers,
                                                          mm_plugin_get_name (self),
                                                          vendor,
                                                          product));
    }
#endif

    return MM_BASE_MODEM (mm_broadband_modem_huawei_new (sysfs_path,
                                                         drivers,
                                                         mm_plugin_get_name (self),
                                                         vendor,
                                                         product));
}
static void
cgclass_update_ready (MMBaseModem *self,
                      GAsyncResult *res,
                      SetAllowedModesContext *ctx)
{
    GError *error = NULL;

    mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
    if (error) {
        /* Let the error be critical. */
        g_simple_async_result_take_error (ctx->result, error);
        set_allowed_modes_context_complete_and_free (ctx);
        return;
    }

    if (!ctx->wwsm_command) {
        g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
        set_allowed_modes_context_complete_and_free (ctx);
        return;
    }

    mm_base_modem_at_command (MM_BASE_MODEM (self),
                              ctx->wwsm_command,
                              3,
                              FALSE,
                              (GAsyncReadyCallback)wwsm_update_ready,
                              ctx);
}
static void
load_current_bands (MMIfaceModem *self,
                    GAsyncReadyCallback callback,
                    gpointer user_data)
{
    GSimpleAsyncResult *result;

    result = g_simple_async_result_new (G_OBJECT (self),
                                        callback,
                                        user_data,
                                        load_current_bands);

    if (mm_iface_modem_is_3g (self))
        mm_base_modem_at_command (MM_BASE_MODEM (self),
                                  "AT+WUBS?",
                                  3,
                                  FALSE,
                                  (GAsyncReadyCallback)get_3g_band_ready,
                                  result);
    else
        mm_base_modem_at_command (MM_BASE_MODEM (self),
                                  "AT+WMBS?",
                                  3,
                                  FALSE,
                                  (GAsyncReadyCallback)get_2g_band_ready,
                                  result);
}
static void
get_ip_config_3gpp (MMBroadbandBearer *self,
                    MMBroadbandModem *modem,
                    MMAtSerialPort *primary,
                    MMAtSerialPort *secondary,
                    MMPort *data,
                    guint cid,
                    GAsyncReadyCallback callback,
                    gpointer user_data)
{
    gchar *command;

    command = g_strdup_printf ("AT_OWANDATA=%d", cid);
    mm_base_modem_at_command_full (MM_BASE_MODEM (modem),
                                   primary,
                                   command,
                                   3,
                                   FALSE,
                                   NULL, /* cancellable */
                                   (GAsyncReadyCallback)ip_config_ready,
                                   get_ip_config_3gpp_context_new (MM_BROADBAND_BEARER_HSO (self),
                                                                   MM_BASE_MODEM (modem),
                                                                   primary,
                                                                   cid,
                                                                   callback,
                                                                   user_data));
    g_free (command);
}
Ejemplo n.º 5
0
static MMBaseModem *
create_modem (MMPlugin *self,
              const gchar *sysfs_path,
              const gchar **drivers,
              guint16 vendor,
              guint16 product,
              GList *probes,
              GError **error)
{
#if defined WITH_QMI
    if (mm_port_probe_list_has_qmi_port (probes)) {
        mm_dbg ("QMI-powered Sierra modem found...");
        return MM_BASE_MODEM (mm_broadband_modem_qmi_new (sysfs_path,
                                                          drivers,
                                                          mm_plugin_get_name (self),
                                                          vendor,
                                                          product));
    }
#endif

    if (sierra_port_probe_list_is_icera (probes))
        return MM_BASE_MODEM (mm_broadband_modem_sierra_icera_new (sysfs_path,
                                                                   drivers,
                                                                   mm_plugin_get_name (self),
                                                                   vendor,
                                                                   product));

    return MM_BASE_MODEM (mm_broadband_modem_sierra_new (sysfs_path,
                                                         drivers,
                                                         mm_plugin_get_name (self),
                                                         vendor,
                                                         product));
}
static void
setup_flow_control (MMIfaceModem *self,
                    GAsyncReadyCallback callback,
                    gpointer user_data)
{
    GSimpleAsyncResult *result;
    gchar *cmd;
    guint flow_control = 1; /* Default flow control: XON/XOFF */

    switch (mm_base_modem_get_product_id (MM_BASE_MODEM (self)) & 0xFFFF) {
    case 0x0021:
        flow_control = 2; /* Telit IMC modems support only RTS/CTS mode */
        break;
    default:
        break;
    }

    cmd = g_strdup_printf ("+IFC=%u,%u", flow_control, flow_control);
    mm_base_modem_at_command (MM_BASE_MODEM (self),
                              cmd,
                              3,
                              FALSE,
                              NULL,
                              NULL);
    result = g_simple_async_result_new (G_OBJECT (self),
                                        callback,
                                        user_data,
                                        setup_flow_control);
    g_simple_async_result_set_op_res_gboolean (result, TRUE);
    g_simple_async_result_complete_in_idle (result);
    g_object_unref (result);
    g_free (cmd);
}
Ejemplo n.º 7
0
MM_PLUGIN_DEFINE_MAJOR_VERSION
MM_PLUGIN_DEFINE_MINOR_VERSION

/*****************************************************************************/

static MMBaseModem *
create_modem (MMPlugin *self,
              const gchar *sysfs_path,
              const gchar **drivers,
              guint16 vendor,
              guint16 product,
              GList *probes,
              GError **error)
{
#if defined WITH_QMI
    if (mm_port_probe_list_has_qmi_port (probes)) {
        mm_dbg ("QMI-powered SimTech modem found...");
        return MM_BASE_MODEM (mm_broadband_modem_qmi_new (sysfs_path,
                                                          drivers,
                                                          mm_plugin_get_name (self),
                                                          vendor,
                                                          product));
    }
#endif

    return MM_BASE_MODEM (mm_broadband_modem_simtech_new (sysfs_path,
                                                          drivers,
                                                          mm_plugin_get_name (self),
                                                          vendor,
                                                          product));
}
static void
setup_ports (MMBroadbandModem *self)
{
    MMAtSerialPort *ports[2];
    guint i;

    /* Call parent's setup ports first always */
    MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_zte_icera_parent_class)->setup_ports (self);

    ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
    ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));

    /* Configure AT ports */
    for (i = 0; i < 2; i++) {
        if (!ports[i])
            continue;

        g_object_set (ports[i],
                      MM_PORT_CARRIER_DETECT, FALSE,
                      NULL);
    }

    /* Now reset the unsolicited messages we'll handle when enabled */
    mm_common_zte_set_unsolicited_events_handlers (MM_BROADBAND_MODEM (self),
                                                   MM_BROADBAND_MODEM_ZTE_ICERA (self)->priv->unsolicited_setup,
                                                   FALSE);
}
static void
modem_power_down (MMIfaceModem *self,
                  GAsyncReadyCallback callback,
                  gpointer user_data)
{
    GSimpleAsyncResult *result;

    result = g_simple_async_result_new (G_OBJECT (self),
                                        callback,
                                        user_data,
                                        mm_common_sierra_modem_power_up);

    /* For CDMA modems, run !pcstate */
    if (mm_iface_modem_is_cdma_only (self)) {
        mm_base_modem_at_command (MM_BASE_MODEM (self),
                                  "!pcstate=0",
                                  5,
                                  FALSE,
                                  (GAsyncReadyCallback)modem_power_down_ready,
                                  result);
        return;
    }

    /* For GSM modems, run AT+CFUN=4 (power save) */
    mm_base_modem_at_command (MM_BASE_MODEM (self),
                              "+CFUN=4",
                              3,
                              FALSE,
                              (GAsyncReadyCallback)modem_power_down_ready,
                              result);
}
static void
setup_ports (MMBroadbandModem *_self)
{
    MMBroadbandModemMbm *self = MM_BROADBAND_MODEM_MBM (_self);
    MMPortSerialAt *ports[2];
    guint i;

    /* Call parent's setup ports first always */
    MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_mbm_parent_class)->setup_ports (_self);

    ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
    ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));

    /* Setup unsolicited handlers which should be always on */
    for (i = 0; i < 2; i++) {
        if (!ports[i])
            continue;

        /* The Ericsson modems always have a free AT command port, so we
         * don't need to flash the ports when disconnecting to get back to
         * command mode.  F5521gw R2A07 resets port properties like echo when
         * flashed, leading to confusion.  bgo #650740
         */
        g_object_set (G_OBJECT (ports[i]),
                      MM_PORT_SERIAL_FLASH_OK, FALSE,
                      NULL);

        mm_port_serial_at_add_unsolicited_msg_handler (
            ports[i],
            self->priv->emrdy_regex,
            (MMPortSerialAtUnsolicitedMsgFn)emrdy_received,
            self,
            NULL);

        /* Several unsolicited messages to always ignore... */
        mm_port_serial_at_add_unsolicited_msg_handler (
            ports[i],
            self->priv->pacsp_regex,
            NULL, NULL, NULL);

        mm_port_serial_at_add_unsolicited_msg_handler (
            ports[i],
            self->priv->estksmenu_regex,
            NULL, NULL, NULL);

        mm_port_serial_at_add_unsolicited_msg_handler (
            ports[i],
            self->priv->estksms_regex,
            NULL, NULL, NULL);

        mm_port_serial_at_add_unsolicited_msg_handler (
            ports[i],
            self->priv->emwi_regex,
            NULL, NULL, NULL);
    }

    /* Now reset the unsolicited messages we'll handle when enabled */
    set_unsolicited_events_handlers (MM_BROADBAND_MODEM_MBM (self), FALSE);
}
static void
run_enabling_init_sequence (EnablingModemInitContext *ctx)
{
    mm_base_modem_at_sequence_full (MM_BASE_MODEM (ctx->self),
                                    mm_base_modem_peek_port_primary (MM_BASE_MODEM (ctx->self)),
                                    enabling_modem_init_sequence,
                                    NULL,  /* response_processor_context */
                                    NULL,  /* response_processor_context_free */
                                    NULL, /* cancellable */
                                    (GAsyncReadyCallback)enabling_init_sequence_ready,
                                    ctx);
}
static void
load_access_technologies_step (AccessTechnologiesContext *ctx)
{
    switch (ctx->step) {
    case ACCESS_TECHNOLOGIES_STEP_FIRST:
        /* Go on to next step */
        ctx->step++;

    case ACCESS_TECHNOLOGIES_STEP_OSSYS:
        mm_base_modem_at_command (MM_BASE_MODEM (ctx->self),
                                  "_OSSYS?",
                                  3,
                                  FALSE,
                                  (GAsyncReadyCallback)ossys_query_ready,
                                  ctx);
        break;

    case ACCESS_TECHNOLOGIES_STEP_OCTI:
        if (ctx->check_2g) {
            mm_base_modem_at_command (MM_BASE_MODEM (ctx->self),
                                      "_OCTI?",
                                      3,
                                      FALSE,
                                      (GAsyncReadyCallback)octi_query_ready,
                                      ctx);
            return;
        }
        /* Go on to next step */
        ctx->step++;

    case ACCESS_TECHNOLOGIES_STEP_OWCTI:
        if (ctx->check_3g) {
            mm_base_modem_at_command (MM_BASE_MODEM (ctx->self),
                                      "_OWCTI?",
                                      3,
                                      FALSE,
                                      (GAsyncReadyCallback)owcti_query_ready,
                                      ctx);
            return;
        }
        /* Go on to next step */
        ctx->step++;

    case ACCESS_TECHNOLOGIES_STEP_LAST:
        /* All done, set result and complete */
        g_simple_async_result_set_op_res_gpointer (ctx->result,
                                                   GUINT_TO_POINTER (ctx->access_technology),
                                                   NULL);
        access_technologies_context_complete_and_free (ctx);
        break;
    }
}
static void
set_unsolicited_events_handlers (MMBroadbandModemOption *self,
                                 gboolean enable)
{
    MMPortSerialAt *ports[2];
    guint i;

    ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
    ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));

    /* Enable unsolicited events in given port */
    for (i = 0; i < 2; i++) {
        if (!ports[i])
            continue;

        /* Access technology related */
        mm_port_serial_at_add_unsolicited_msg_handler (
            ports[i],
            self->priv->_ossysi_regex,
            enable ? (MMPortSerialAtUnsolicitedMsgFn)option_ossys_tech_changed : NULL,
            enable ? self : NULL,
            NULL);
        mm_port_serial_at_add_unsolicited_msg_handler (
            ports[i],
            self->priv->_octi_regex,
            enable ? (MMPortSerialAtUnsolicitedMsgFn)option_2g_tech_changed : NULL,
            enable ? self : NULL,
            NULL);
        mm_port_serial_at_add_unsolicited_msg_handler (
            ports[i],
            self->priv->_ouwcti_regex,
            enable ? (MMPortSerialAtUnsolicitedMsgFn)option_3g_tech_changed : NULL,
            enable ? self : NULL,
            NULL);

        /* Signal quality related */
        mm_port_serial_at_add_unsolicited_msg_handler (
            ports[i],
            self->priv->_osigq_regex,
            enable ? (MMPortSerialAtUnsolicitedMsgFn)option_signal_changed : NULL,
            enable ? self : NULL,
            NULL);

        /* Other unsolicited events to always ignore */
        if (!enable)
            mm_port_serial_at_add_unsolicited_msg_handler (
                ports[i],
                self->priv->ignore_regex,
                NULL, NULL, NULL);
    }
}
static void
modem_3gpp_enable_unsolicited_events (MMIfaceModem3gpp *self,
                                      GAsyncReadyCallback callback,
                                      gpointer user_data)
{
    mm_base_modem_at_sequence_full (
        MM_BASE_MODEM (self),
        mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self)),
        unsolicited_enable_sequence,
        NULL,  /* response_processor_context */
        NULL,  /* response_processor_context_free */
        NULL,  /* cancellable */
        callback,
        user_data);
}
static void
load_current_modes (MMIfaceModem *self,
                    GAsyncReadyCallback callback,
                    gpointer user_data)
{
    GSimpleAsyncResult *result;

    result = g_simple_async_result_new (G_OBJECT (self),
                                        callback,
                                        user_data,
                                        load_current_modes);

    /* Load allowed modes only in 3GPP modems */
    if (!mm_iface_modem_is_3gpp (self)) {
        g_simple_async_result_set_error (
            result,
            MM_CORE_ERROR,
            MM_CORE_ERROR_UNSUPPORTED,
            "Loading allowed modes not supported in CDMA-only modems");
        g_simple_async_result_complete_in_idle (result);
        g_object_unref (result);
        return;
    }

    mm_base_modem_at_command (MM_BASE_MODEM (self),
                              "$NWRAT?",
                              3,
                              FALSE,
                              (GAsyncReadyCallback)nwrat_query_ready,
                              result);
}
static gboolean
modem_time_check_support_finish (MMIfaceModemTime *self,
                                 GAsyncResult *res,
                                 GError **error)
{
    return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
}
static void
modem_cdma_get_detailed_registration_state (MMIfaceModemCdma *self,
                                            MMModemCdmaRegistrationState cdma1x_state,
                                            MMModemCdmaRegistrationState evdo_state,
                                            GAsyncReadyCallback callback,
                                            gpointer user_data)
{
    DetailedRegistrationStateContext *ctx;
    GByteArray *nweri;
    MMPortSerialQcdm *port;

    /* Setup context */
    ctx = g_new0 (DetailedRegistrationStateContext, 1);
    ctx->self = g_object_ref (self);
    ctx->result = g_simple_async_result_new (G_OBJECT (self),
                                             callback,
                                             user_data,
                                             modem_cdma_get_detailed_registration_state);
    ctx->state.detailed_cdma1x_state = cdma1x_state;
    ctx->state.detailed_evdo_state = evdo_state;

    port = mm_base_modem_peek_port_qcdm (MM_BASE_MODEM (self));

    /* Try MSM6800 first since newer cards use that */
    nweri = g_byte_array_sized_new (25);
    nweri->len = qcdm_cmd_nw_subsys_eri_new ((char *) nweri->data, 25, QCDM_NW_CHIPSET_6800);
    g_assert (nweri->len);
    mm_port_serial_qcdm_command (port,
                                 nweri,
                                 3,
                                 NULL,
                                 (GAsyncReadyCallback)reg_eri_6800_cb,
                                 ctx);
    g_byte_array_unref (nweri);
}
static gboolean
modem_init_finish (MMIfaceModem *self,
                   GAsyncResult *res,
                   GError **error)
{
    return !mm_base_modem_at_sequence_finish (MM_BASE_MODEM (self), res, NULL, error);
}
static void
setup_flow_control (MMIfaceModem *self,
                    GAsyncReadyCallback callback,
                    gpointer user_data)
{
    GSimpleAsyncResult *result;

    result = g_simple_async_result_new (G_OBJECT (self),
                                        callback,
                                        user_data,
                                        setup_flow_control);

    /* Enable RTS/CTS flow control.
     * Other available values:
     *   AT&K0: Disable flow control
     *   AT&K3: RTS/CTS
     *   AT&K4: XOFF/XON
     *   AT&K6: Both RTS/CTS and XOFF/XON
     */
    mm_base_modem_at_command (MM_BASE_MODEM (self),
                              "&K3",
                              3,
                              FALSE,
                              (GAsyncReadyCallback)setup_flow_control_ready,
                              result);
}
static guint
load_signal_quality_finish (MMIfaceModem *self,
                            GAsyncResult *res,
                            GError **error)
{
    gint quality = 0;
    const gchar *result;

    result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
    if (!result)
        return 0;

    /* Skip possible whitespaces after '+CSQF:' and before the response */
    result = mm_strip_tag (result, "+CSQF:");
    while (*result == ' ')
        result++;

    if (sscanf (result, "%d", &quality))
        /* Normalize the quality. <rssi> is NOT given in dBs,
         * given as a relative value between 0 and 5 */
        quality = CLAMP (quality, 0, 5) * 100 / 5;
    else
        g_set_error (error,
                     MM_CORE_ERROR,
                     MM_CORE_ERROR_FAILED,
                     "Could not parse signal quality results");

    return quality;
}
static void
connect_3gpp_qmiconnect_ready (MMBaseModem *modem,
                               GAsyncResult *res,
                               DetailedConnectContext *ctx)
{
    const gchar *result;
    GError *error = NULL;

    result = mm_base_modem_at_command_finish (MM_BASE_MODEM (modem),
                                              res,
                                              &error);
    if (!result) {
        mm_warn ("QMI connection failed: %s", error->message);
        g_simple_async_result_take_error (ctx->result, error);
        detailed_connect_context_complete_and_free (ctx);
        return;
    }

    /*
     * The connection takes a bit of time to set up, but there's no
     * asynchronous notification from the modem when this has
     * happened. Instead, we need to poll the modem to see if it's
     * ready.
     */
    g_timeout_add_seconds(1, (GSourceFunc)connect_3gpp_qmistatus, ctx);
}
static void
set_current_modes (MMIfaceModem *self,
                   MMModemMode allowed,
                   MMModemMode preferred,
                   GAsyncReadyCallback callback,
                   gpointer user_data)
{
    GSimpleAsyncResult *result;
    gchar *command;
    gint mododr = 0;

    result = g_simple_async_result_new (G_OBJECT (self),
                                        callback,
                                        user_data,
                                        set_current_modes);

    if (allowed == MM_MODEM_MODE_2G)
        mododr = 3;
    else if (allowed == MM_MODEM_MODE_3G)
        mododr = 1;
    else if (allowed == (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G)) {
        if (preferred == MM_MODEM_MODE_2G)
            mododr = 4;
        else if (preferred == MM_MODEM_MODE_3G)
            mododr = 2;
    } else if (allowed == MM_MODEM_MODE_ANY && preferred == MM_MODEM_MODE_NONE)
        /* Default to 3G preferred */
        mododr = 2;

    if (mododr == 0) {
        gchar *allowed_str;
        gchar *preferred_str;

        allowed_str = mm_modem_mode_build_string_from_mask (allowed);
        preferred_str = mm_modem_mode_build_string_from_mask (preferred);
        g_simple_async_result_set_error (result,
                                         MM_CORE_ERROR,
                                         MM_CORE_ERROR_FAILED,
                                         "Requested mode (allowed: '%s', preferred: '%s') not "
                                         "supported by the modem.",
                                         allowed_str,
                                         preferred_str);
        g_free (allowed_str);
        g_free (preferred_str);

        g_simple_async_result_complete_in_idle (result);
        g_object_unref (result);
        return;
    }

    command = g_strdup_printf ("+MODODR=%d", mododr);
    mm_base_modem_at_command (
        MM_BASE_MODEM (self),
        command,
        3,
        FALSE,
        (GAsyncReadyCallback)allowed_mode_update_ready,
        result);
    g_free (command);
}
static gboolean
modem_power_down_finish (MMIfaceModem *self,
                         GAsyncResult *res,
                         GError **error)
{
    return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
}
static void
modem_load_signal_quality (MMIfaceModem *self,
                           GAsyncReadyCallback callback,
                           gpointer user_data)
{
    GSimpleAsyncResult *result;

    mm_dbg ("loading signal quality...");
    result = g_simple_async_result_new (G_OBJECT (self),
                                        callback,
                                        user_data,
                                        modem_load_signal_quality);

    /* 3GPP modems can just run parent's signal quality loading */
    if (mm_iface_modem_is_3gpp (self)) {
        iface_modem_parent->load_signal_quality (
            self,
            (GAsyncReadyCallback)parent_load_signal_quality_ready,
            result);
        return;
    }

    /* CDMA modems need custom signal quality loading */
    mm_base_modem_at_command (
        MM_BASE_MODEM (self),
        "$NWRSSI",
        3,
        FALSE,
        (GAsyncReadyCallback)nwrssi_ready,
        result);
}
static void
setup_ports (MMBroadbandModem *self)
{
    gpointer parser;
    MMAtSerialPort *primary;
    GRegex *regex;

    /* Call parent's setup ports first always */
    MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_wavecom_parent_class)->setup_ports (self);

    /* Set 9600 baudrate by default in the AT port */
    mm_dbg ("Baudrate will be set to 9600 bps...");
    primary = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
    if (!primary)
        return;

    /* AT+CPIN? replies will never have an OK appended */
    parser = mm_serial_parser_v1_new ();
    regex = g_regex_new ("\\r\\n\\+CPIN: .*\\r\\n",
                         G_REGEX_RAW | G_REGEX_OPTIMIZE,
                         0, NULL);
    mm_serial_parser_v1_set_custom_regex (parser, regex, NULL);
    g_regex_unref (regex);

    mm_at_serial_port_set_response_parser (MM_AT_SERIAL_PORT (primary),
                                           mm_serial_parser_v1_parse,
                                           parser,
                                           mm_serial_parser_v1_destroy);
}
static void
cnti_set_ready (MMBaseModem *self,
                GAsyncResult *res,
                GSimpleAsyncResult *simple)
{
    GError *error = NULL;
    const gchar *response;
    const gchar *p;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
    if (!response) {
        g_simple_async_result_take_error (simple, error);
        g_simple_async_result_complete (simple);
        g_object_unref (simple);
        return;
    }

    p = mm_strip_tag (response, "$CNTI:");
    p = strchr (p, ',');
    if (!p) {
        error = g_error_new (MM_CORE_ERROR,
                             MM_CORE_ERROR_FAILED,
                             "Couldn't parse $CNTI result '%s'",
                             response);
        g_simple_async_result_take_error (simple, error);
        g_simple_async_result_complete (simple);
        g_object_unref (simple);
        return;
    }

    snapshot_result_complete_simple (simple,
                                     mm_string_to_access_tech (p),
                                     MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK);
    g_object_unref (simple);
}
static void
modem_load_access_technologies (MMIfaceModem *self,
                                GAsyncReadyCallback callback,
                                gpointer user_data)
{
    GSimpleAsyncResult *result;

    result = g_simple_async_result_new (G_OBJECT (self),
                                        callback,
                                        user_data,
                                        modem_load_access_technologies);

    /* CDMA-only modems defer to parent for generic access technology
     * checking, but can determine EVDOr0 vs. EVDOrA through proprietary
     * QCDM commands.
     */
    if (mm_iface_modem_is_cdma_only (self)) {
        iface_modem_parent->load_access_technologies (
            self,
            (GAsyncReadyCallback)parent_load_access_technologies_ready,
            result);
        return;
    }

    mm_base_modem_at_command (
        MM_BASE_MODEM (self),
        "$CNTI=0",
        3,
        FALSE,
        (GAsyncReadyCallback)cnti_set_ready,
        result);
}
static DetailedConnectContext *
detailed_connect_context_new (MMBroadbandBearer *self,
                              MMBroadbandModem *modem,
                              MMAtSerialPort *primary,
                              MMPort *data,
                              GCancellable *cancellable,
                              GAsyncReadyCallback callback,
                              gpointer user_data)
{
    DetailedConnectContext *ctx;

    ctx = g_new0 (DetailedConnectContext, 1);
    ctx->self = g_object_ref (self);
    ctx->modem = MM_BASE_MODEM (g_object_ref (modem));
    ctx->primary = g_object_ref (primary);
    ctx->data = g_object_ref (data);
    /* NOTE:
     * We don't currently support cancelling AT commands, so we'll just check
     * whether the operation is to be cancelled at each step. */
    ctx->cancellable = g_object_ref (cancellable);
    ctx->result = g_simple_async_result_new (G_OBJECT (self),
                                             callback,
                                             user_data,
                                             detailed_connect_context_new);
    ctx->retries = 4;
    return ctx;
}
static gboolean
messaging_enable_unsolicited_events_finish (MMIfaceModemMessaging *self,
                                            GAsyncResult *res,
                                            GError **error)
{
    return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
}
static void
enabling_modem_init (MMBroadbandModem *self,
                     GAsyncReadyCallback callback,
                     gpointer user_data)
{
    EnablingModemInitContext *ctx;

    ctx = g_slice_new0 (EnablingModemInitContext);
    ctx->result = g_simple_async_result_new (G_OBJECT (self),
                                             callback,
                                             user_data,
                                             enabling_modem_init);
    ctx->self = g_object_ref (self);

    /* Modem is ready?, no need to check EMRDY */
    if (ctx->self->priv->have_emrdy) {
        run_enabling_init_sequence (ctx);
        return;
    }

    mm_base_modem_at_command (MM_BASE_MODEM (self),
                              "*EMRDY?",
                              3,
                              FALSE,
                              (GAsyncReadyCallback)emrdy_ready,
                              ctx);
}