static void
reg_eri_6500_cb (MMPortSerialQcdm *port,
                 GAsyncResult *res,
                 DetailedRegistrationStateContext *ctx)
{
    GError *error = NULL;
    GByteArray *response;

    response = mm_port_serial_qcdm_command_finish (port, res, &error);
    if (error) {
        /* Just ignore the error and complete with the input info */
        mm_dbg ("Couldn't run QCDM MSM6500 ERI: '%s'", error->message);
        g_error_free (error);
    } else {
        QcdmResult *result;

        result = qcdm_cmd_nw_subsys_eri_result ((const gchar *) response->data, response->len, NULL);
        g_byte_array_unref (response);
        if (result) {
            parse_modem_eri (ctx, result);
            qcdm_result_unref (result);
        }
    }

    /* NOTE: always complete NOT in idle here */
    g_simple_async_result_set_op_res_gpointer (ctx->result, &ctx->state, NULL);
    detailed_registration_state_context_complete_and_free (ctx);
}
static void
reg_eri_6800_cb (MMPortSerialQcdm *port,
                 GAsyncResult *res,
                 DetailedRegistrationStateContext *ctx)
{
    GError *error = NULL;
    GByteArray *response;

    response = mm_port_serial_qcdm_command_finish (port, res, &error);
    if (error) {
        /* Just ignore the error and complete with the input info */
        mm_dbg ("Couldn't run QCDM MSM6800 ERI: '%s'", error->message);
        g_error_free (error);
    } else {
        QcdmResult *result;

        /* Parse the response */
        result = qcdm_cmd_nw_subsys_eri_result ((const gchar *) response->data, response->len, NULL);
        g_byte_array_unref (response);
        if (result) {
            parse_modem_eri (ctx, result);
            qcdm_result_unref (result);
        } else {
            GByteArray *nweri;

            /* Try for MSM6500 */
            nweri = g_byte_array_sized_new (25);
            nweri->len = qcdm_cmd_nw_subsys_eri_new ((char *) nweri->data, 25, QCDM_NW_CHIPSET_6500);
            g_assert (nweri->len);
            mm_port_serial_qcdm_command (port,
                                         nweri,
                                         3,
                                         NULL,
                                         (GAsyncReadyCallback)reg_eri_6500_cb,
                                         ctx);
            g_byte_array_unref (nweri);
            return;
        }
    }

    /* NOTE: always complete NOT in idle here */
    g_simple_async_result_set_op_res_gpointer (ctx->result, &ctx->state, NULL);
    detailed_registration_state_context_complete_and_free (ctx);
}
static void
status_ready (MMIfaceModemCdma *self,
              GAsyncResult *res,
              DetailedRegistrationStateContext *ctx)
{
    GError *error = NULL;
    const gchar *response;
    gchar **lines;
    gchar **iter;
    gboolean registered = FALSE;
    gboolean have_sid = FALSE;
    SysMode evdo_mode = SYS_MODE_UNKNOWN;
    SysMode sys_mode = SYS_MODE_UNKNOWN;
    gboolean evdo_roam = FALSE, cdma1x_roam = FALSE;

    response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
    /* If error, leave superclass' reg state alone if AT!STATUS isn't supported. */
    if (error) {
        g_error_free (error);

        /* NOTE: always complete NOT in idle here */
        g_simple_async_result_set_op_res_gpointer (ctx->result, &ctx->state, NULL);
        detailed_registration_state_context_complete_and_free (ctx);
        return;
    }

    lines = g_strsplit_set (response, "\n\r", 0);
    if (!lines) {
        /* NOTE: always complete NOT in idle here */
        g_simple_async_result_set_op_res_gpointer (ctx->result, &ctx->state, NULL);
        detailed_registration_state_context_complete_and_free (ctx);
        return;
    }

    /* Sierra CDMA parts have two general formats depending on whether they
     * support EVDO or not.  EVDO parts report both 1x and EVDO roaming status
     * while of course 1x parts only report 1x status.  Some modems also do not
     * report the Roaming information (MP 555 GPS).
     *
     * AT!STATUS responses:
     *
     * Unregistered MC5725:
     * -----------------------
     * Current band: PCS CDMA
     * Current channel: 350
     * SID: 0  NID: 0  1xRoam: 0 HDRRoam: 0
     * Temp: 33  State: 100  Sys Mode: NO SRV
     * Pilot NOT acquired
     * Modem has NOT registered
     *
     * Registered MC5725:
     * -----------------------
     * Current band: Cellular Sleep
     * Current channel: 775
     * SID: 30  NID: 2  1xRoam: 0 HDRRoam: 0
     * Temp: 29  State: 200  Sys Mode: HDR
     * Pilot acquired
     * Modem has registered
     * HDR Revision: A
     *
     * Unregistered AC580:
     * -----------------------
     * Current band: PCS CDMA
     * Current channel: 350
     * SID: 0 NID: 0  Roaming: 0
     * Temp: 39  State: 100  Scan Mode: 0
     * Pilot NOT acquired
     * Modem has NOT registered
     *
     * Registered AC580:
     * -----------------------
     * Current band: Cellular Sleep
     * Current channel: 548
     * SID: 26  NID: 1  Roaming: 1
     * Temp: 39  State: 200  Scan Mode: 0
     * Pilot Acquired
     * Modem has registered
     */

    /* We have to handle the two formats slightly differently; for newer formats
     * with "Sys Mode", we consider the modem registered if the Sys Mode is not
     * "NO SRV".  The explicit registration status is just icing on the cake.
     * For older formats (no "Sys Mode") we treat the modem as registered if
     * the SID is non-zero.
     */

    for (iter = lines; iter && *iter; iter++) {
        gboolean bool_val = FALSE;
        char *p;

        if (!strncmp (*iter, MODEM_REG_TAG, strlen (MODEM_REG_TAG))) {
            registered = TRUE;
            continue;
        }

        /* Roaming */
        get_roam_value (*iter, ROAM_1X_TAG, TRUE, &cdma1x_roam);
        get_roam_value (*iter, ROAM_EVDO_TAG, TRUE, &evdo_roam);
        if (get_roam_value (*iter, GENERIC_ROAM_TAG, FALSE, &bool_val))
            cdma1x_roam = evdo_roam = bool_val;

        /* Current system mode */
        p = strstr (*iter, SYS_MODE_TAG);
        if (p) {
            p += strlen (SYS_MODE_TAG);
            while (*p && isspace (*p))
                p++;
            if (!strncmp (p, SYS_MODE_NO_SERVICE_TAG, strlen (SYS_MODE_NO_SERVICE_TAG)))
                sys_mode = SYS_MODE_NO_SERVICE;
            else if (!strncmp (p, SYS_MODE_EVDO_TAG, strlen (SYS_MODE_EVDO_TAG)))
                sys_mode = SYS_MODE_EVDO_REV0;
            else if (   !strncmp (p, SYS_MODE_1X_TAG, strlen (SYS_MODE_1X_TAG))
                     || !strncmp (p, SYS_MODE_CDMA_TAG, strlen (SYS_MODE_CDMA_TAG)))
                sys_mode = SYS_MODE_CDMA_1X;
        }

        /* Current EVDO revision if system mode is EVDO */
        p = strstr (*iter, EVDO_REV_TAG);
        if (p) {
            p += strlen (EVDO_REV_TAG);
            while (*p && isspace (*p))
                p++;
            if (*p == 'A')
                evdo_mode = SYS_MODE_EVDO_REVA;
            else if (*p == '0')
                evdo_mode = SYS_MODE_EVDO_REV0;
        }

        /* SID */
        p = strstr (*iter, SID_TAG);
        if (p) {
            p += strlen (SID_TAG);
            while (*p && isspace (*p))
                p++;
            if (isdigit (*p) && (*p != '0'))
                have_sid = TRUE;
        }
    }

    /* Update current system mode */
    if (sys_mode_is_evdo (sys_mode)) {
        /* Prefer the explicit EVDO mode from EVDO_REV_TAG */
        if (evdo_mode != SYS_MODE_UNKNOWN)
            sys_mode = evdo_mode;
    }

    /* If the modem didn't report explicit registration with "Modem has
     * registered" then get registration status by looking at either system
     * mode or (for older devices that don't report that) just the SID.
     */
    if (!registered) {
        if (sys_mode != SYS_MODE_UNKNOWN)
            registered = sys_mode_has_service (sys_mode);
        else
            registered = have_sid;
    }

    if (registered) {
        ctx->state.detailed_cdma1x_state = (cdma1x_roam ?
                                            MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING :
                                            MM_MODEM_CDMA_REGISTRATION_STATE_HOME);

        if (sys_mode_is_evdo (sys_mode)) {
            ctx->state.detailed_evdo_state = (evdo_roam ?
                                              MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING :
                                              MM_MODEM_CDMA_REGISTRATION_STATE_HOME);
        } else {
            ctx->state.detailed_evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
        }
    } else {
        /* Not registered */
        ctx->state.detailed_cdma1x_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
        ctx->state.detailed_evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
    }

    /* NOTE: always complete NOT in idle here */
    g_simple_async_result_set_op_res_gpointer (ctx->result, &ctx->state, NULL);
    detailed_registration_state_context_complete_and_free (ctx);
}