aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2010-03-23 02:10:58 -0700
committerDan Williams <dcbw@redhat.com>2010-03-23 02:10:58 -0700
commite7d1e4adb9bf984736ae2bfadbdd616ebc6ade80 (patch)
treef2356de3f6b6de0c85e9e31051b2bb2eee071064
parentbcfb75d88de4679d1ca2dfc65395c49315534ec0 (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.c84
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);
}
/*****************************************************************************/