diff options
author | Dan Williams <dcbw@redhat.com> | 2010-03-23 02:10:58 -0700 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2010-03-23 02:10:58 -0700 |
commit | e7d1e4adb9bf984736ae2bfadbdd616ebc6ade80 (patch) | |
tree | f2356de3f6b6de0c85e9e31051b2bb2eee071064 | |
parent | bcfb75d88de4679d1ca2dfc65395c49315534ec0 (diff) |
cdma: use DM Call Manager for registration status if available
This should solve problems with users who's providers are EVDO
only and thus the device isn't in 1X mode, but who's modems
don't set anything meaningful for CAD or CSS when the 1X radio
isn't registered. Previously, MM would just spin thinking it
wasn't registered when trying to connect.
This was mostly found with AnyDATA, Huawei, and some ZTE devices
from Russia and India.
-rw-r--r-- | src/mm-generic-cdma.c | 84 |
1 files changed, 82 insertions, 2 deletions
diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index d2c030f4..35fcce97 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -29,6 +29,7 @@ #include "mm-callback-info.h" #include "mm-serial-parsers.h" #include "mm-modem-helpers.h" +#include "libqcdm/src/commands.h" #define MM_GENERIC_CDMA_PREV_STATE_TAG "prev-state" @@ -1412,6 +1413,73 @@ error: } static void +reg_cmstate_cb (MMQcdmSerialPort *port, + GByteArray *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + MMAtSerialPort *at_port; + QCDMResult *result; + guint32 opmode = 0, sysmode = 0; + MMModemCdmaRegistrationState cdma_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; + MMModemCdmaRegistrationState evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; + + if (error) + goto error; + + /* Parse the response */ + result = qcdm_cmd_cm_subsys_state_info_result ((const char *) response->data, response->len, &info->error); + if (!result) + goto error; + + qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_OPERATING_MODE, &opmode); + qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SYSTEM_MODE, &sysmode); + qcdm_result_unref (result); + + if (opmode == QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_ONLINE) { + switch (sysmode) { + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_CDMA: + cdma_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; + break; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_HDR: + evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; + break; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_AMPS: + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_NO_SERVICE: + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_WCDMA: + default: + break; + } + + if (cdma_state || evdo_state) { + /* Device is registered to something; see if the subclass has a + * better idea of whether we're roaming or not and what the + * access technology is. + */ + if (MM_GENERIC_CDMA_GET_CLASS (info->modem)->query_registration_state) + MM_GENERIC_CDMA_GET_CLASS (info->modem)->query_registration_state (MM_GENERIC_CDMA (info->modem), + reg_state_query_done, + info); + return; + } + } + + set_callback_1x_state_helper (info, cdma_state); + set_callback_evdo_state_helper (info, evdo_state); + mm_callback_info_schedule (info); + return; + +error: + /* If there was some error, fall back to use +CAD like we did before QCDM */ + at_port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (info->modem), &info->error); + if (at_port) + mm_at_serial_port_queue_command (at_port, "+CAD?", 3, get_analog_digital_done, info); + else + mm_callback_info_schedule (info); +} + +static void get_registration_state (MMModemCdma *modem, MMModemCdmaRegistrationStateFn callback, gpointer user_data) @@ -1423,7 +1491,7 @@ get_registration_state (MMModemCdma *modem, info = mm_generic_cdma_query_reg_state_callback_info_new (MM_GENERIC_CDMA (modem), callback, user_data); port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (modem), &info->error); - if (!port) { + if (!port && !priv->qcdm) { g_message ("Returning saved registration states: 1x: %d EVDO: %d", priv->cdma_1x_reg_state, priv->evdo_reg_state); mm_callback_info_set_data (info, @@ -1438,7 +1506,19 @@ get_registration_state (MMModemCdma *modem, return; } - mm_at_serial_port_queue_command (port, "+CAD?", 3, get_analog_digital_done, info); + /* Use QCDM for Call Manager state or HDR state before trying CAD, since + * CAD doesn't always reflect the state of the HDR radio's registration + * status. + */ + if (priv->qcdm) { + GByteArray *cmstate; + + cmstate = g_byte_array_sized_new (25); + cmstate->len = qcdm_cmd_cm_subsys_state_info_new ((char *) cmstate->data, 25, NULL); + g_assert (cmstate->len); + mm_qcdm_serial_port_queue_command (priv->qcdm, cmstate, 3, reg_cmstate_cb, info); + } else + mm_at_serial_port_queue_command (port, "+CAD?", 3, get_analog_digital_done, info); } /*****************************************************************************/ |