broadband-modem: guess CDMA access technologies from registration state

Setting access technologies from registration state as part of the
registration checking in the CDMA Interface code fights with
custom implementations in each modem subclass, which causes the
access technologies to ping-pong between more specific (custom
implementation) and less specific (generated from registration state
during registration checking).  If the modem class has more
specific access technology knowledge, we should use that and not
override it on the next registration state poll.

So instead, implement the generic access technology update from
registration state in the broadband modem base class'
load_access_technologies() hook.  Thus, modem classes with more
specific checking (which override MMBroadbandModem's implementation)
will never fight with generic checking, while modems that don't
(and thus actually need the generic checking) still get some basic
access technology handling.
This commit is contained in:
Dan Williams
2013-01-08 14:41:51 -06:00
parent edeb75b028
commit fdad4d636d
2 changed files with 82 additions and 51 deletions

View File

@@ -1784,15 +1784,25 @@ typedef struct {
gboolean wcdma_open; gboolean wcdma_open;
gboolean evdo_open; gboolean evdo_open;
MMModemAccessTechnology fallback_act;
guint fallback_mask;
} AccessTechContext; } AccessTechContext;
static void static void
access_tech_context_complete_and_free (AccessTechContext *ctx) access_tech_context_complete_and_free (AccessTechContext *ctx, gboolean idle)
{ {
AccessTechAndMask *tech; AccessTechAndMask *tech;
MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
guint mask = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; guint mask = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
if (ctx->fallback_mask) {
mm_dbg ("Fallback access technology: 0x%08x", ctx->fallback_act);
act = ctx->fallback_act;
mask = ctx->fallback_mask;
goto done;
}
mm_dbg ("QCDM operating mode: %d", ctx->opmode); mm_dbg ("QCDM operating mode: %d", ctx->opmode);
mm_dbg ("QCDM system mode: %d", ctx->sysmode); mm_dbg ("QCDM system mode: %d", ctx->sysmode);
mm_dbg ("QCDM hybrid pref: %d", ctx->hybrid); mm_dbg ("QCDM hybrid pref: %d", ctx->hybrid);
@@ -1833,12 +1843,16 @@ access_tech_context_complete_and_free (AccessTechContext *ctx)
} }
} }
done:
tech = g_new0 (AccessTechAndMask, 1); tech = g_new0 (AccessTechAndMask, 1);
tech->access_technologies = act; tech->access_technologies = act;
tech->mask = mask; tech->mask = mask;
g_simple_async_result_set_op_res_gpointer (ctx->result, tech, g_free); g_simple_async_result_set_op_res_gpointer (ctx->result, tech, g_free);
g_simple_async_result_complete (ctx->result); if (idle)
g_simple_async_result_complete_in_idle (ctx->result);
else
g_simple_async_result_complete (ctx->result);
g_object_unref (ctx->result); g_object_unref (ctx->result);
g_object_unref (ctx->self); g_object_unref (ctx->self);
@@ -1859,7 +1873,7 @@ access_tech_qcdm_wcdma_ready (MMQcdmSerialPort *port,
if (error) { if (error) {
g_simple_async_result_set_from_error (ctx->result, error); g_simple_async_result_set_from_error (ctx->result, error);
access_tech_context_complete_and_free (ctx); access_tech_context_complete_and_free (ctx, FALSE);
return; return;
} }
@@ -1877,7 +1891,7 @@ access_tech_qcdm_wcdma_ready (MMQcdmSerialPort *port,
ctx->wcdma_open = TRUE; ctx->wcdma_open = TRUE;
} }
access_tech_context_complete_and_free (ctx); access_tech_context_complete_and_free (ctx, FALSE);
} }
static void static void
@@ -1894,7 +1908,7 @@ access_tech_qcdm_gsm_ready (MMQcdmSerialPort *port,
if (error) { if (error) {
g_simple_async_result_set_from_error (ctx->result, error); g_simple_async_result_set_from_error (ctx->result, error);
access_tech_context_complete_and_free (ctx); access_tech_context_complete_and_free (ctx, FALSE);
return; return;
} }
@@ -1908,7 +1922,7 @@ access_tech_qcdm_gsm_ready (MMQcdmSerialPort *port,
MM_CORE_ERROR_FAILED, MM_CORE_ERROR_FAILED,
"Failed to parse GSM subsys command result: %d", "Failed to parse GSM subsys command result: %d",
err); err);
access_tech_context_complete_and_free (ctx); access_tech_context_complete_and_free (ctx, FALSE);
return; return;
} }
@@ -1945,7 +1959,7 @@ access_tech_qcdm_hdr_ready (MMQcdmSerialPort *port,
if (error) { if (error) {
g_simple_async_result_set_from_error (ctx->result, error); g_simple_async_result_set_from_error (ctx->result, error);
access_tech_context_complete_and_free (ctx); access_tech_context_complete_and_free (ctx, FALSE);
return; return;
} }
@@ -1964,7 +1978,7 @@ access_tech_qcdm_hdr_ready (MMQcdmSerialPort *port,
ctx->evdo_open = TRUE; ctx->evdo_open = TRUE;
} }
access_tech_context_complete_and_free (ctx); access_tech_context_complete_and_free (ctx, FALSE);
} }
static void static void
@@ -1980,7 +1994,7 @@ access_tech_qcdm_cdma_ready (MMQcdmSerialPort *port,
if (error) { if (error) {
g_simple_async_result_set_from_error (ctx->result, error); g_simple_async_result_set_from_error (ctx->result, error);
access_tech_context_complete_and_free (ctx); access_tech_context_complete_and_free (ctx, FALSE);
return; return;
} }
@@ -1994,7 +2008,7 @@ access_tech_qcdm_cdma_ready (MMQcdmSerialPort *port,
MM_CORE_ERROR_FAILED, MM_CORE_ERROR_FAILED,
"Failed to parse CM subsys command result: %d", "Failed to parse CM subsys command result: %d",
err); err);
access_tech_context_complete_and_free (ctx); access_tech_context_complete_and_free (ctx, FALSE);
return; return;
} }
@@ -2018,61 +2032,95 @@ access_tech_qcdm_cdma_ready (MMQcdmSerialPort *port,
ctx); ctx);
} }
static void
access_tech_from_cdma_registration_state (MMBroadbandModem *self,
AccessTechContext *ctx)
{
gboolean cdma1x_registered = FALSE;
gboolean evdo_registered = FALSE;
if (self->priv->modem_cdma_evdo_registration_state > MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)
evdo_registered = TRUE;
if (self->priv->modem_cdma_cdma1x_registration_state > MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)
cdma1x_registered = TRUE;
if (self->priv->modem_cdma_evdo_network_supported && evdo_registered) {
ctx->fallback_act = MM_MODEM_ACCESS_TECHNOLOGY_EVDO0;
ctx->fallback_mask = MM_IFACE_MODEM_CDMA_ALL_ACCESS_TECHNOLOGIES_MASK;
} else if (self->priv->modem_cdma_cdma1x_network_supported && cdma1x_registered) {
ctx->fallback_act = MM_MODEM_ACCESS_TECHNOLOGY_1XRTT;
ctx->fallback_mask = MM_IFACE_MODEM_CDMA_ALL_ACCESS_TECHNOLOGIES_MASK;
}
mm_dbg ("EVDO registration: %d", self->priv->modem_cdma_evdo_registration_state);
mm_dbg ("CDMA1x registration: %d", self->priv->modem_cdma_cdma1x_registration_state);
mm_dbg ("Fallback access tech: 0x%08x", ctx->fallback_act);
access_tech_context_complete_and_free (ctx, TRUE);
}
static void static void
modem_load_access_technologies (MMIfaceModem *self, modem_load_access_technologies (MMIfaceModem *self,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
MMQcdmSerialPort *port;
AccessTechContext *ctx; AccessTechContext *ctx;
GByteArray *cmd; GByteArray *cmd;
mm_dbg ("loading access technologies via QCDM..."); mm_dbg ("loading access technologies via QCDM...");
/* For modems where only QCDM provides detailed information, try to /* For modems where only QCDM provides detailed information, try to
* get access technologies via the various QCDM subsystems. * get access technologies via the various QCDM subsystems or from
* registration state
*/ */
port = mm_base_modem_peek_port_qcdm (MM_BASE_MODEM (self));
if (!port) {
g_simple_async_report_error_in_idle (G_OBJECT (self),
callback,
user_data,
MM_CORE_ERROR,
MM_CORE_ERROR_UNSUPPORTED,
"Cannot get access technology without a QCDM port");
return;
}
ctx = g_new0 (AccessTechContext, 1); ctx = g_new0 (AccessTechContext, 1);
ctx->self = g_object_ref (self); ctx->self = g_object_ref (self);
ctx->port = g_object_ref (port); ctx->port = mm_base_modem_get_port_qcdm (MM_BASE_MODEM (self));
ctx->result = g_simple_async_result_new (G_OBJECT (self), ctx->result = g_simple_async_result_new (G_OBJECT (self),
callback, callback,
user_data, user_data,
modem_load_access_technologies); modem_load_access_technologies);
if (!mm_iface_modem_is_cdma (self) && !ctx->port) {
g_simple_async_result_set_error (ctx->result,
MM_CORE_ERROR,
MM_CORE_ERROR_UNSUPPORTED,
"%s",
"Cannot get 3GPP access technology without a QCDM port");
access_tech_context_complete_and_free (ctx, TRUE);
return;
}
if (mm_iface_modem_is_3gpp (self)) { if (mm_iface_modem_is_3gpp (self)) {
cmd = g_byte_array_sized_new (50); cmd = g_byte_array_sized_new (50);
cmd->len = qcdm_cmd_gsm_subsys_state_info_new ((char *) cmd->data, 50); cmd->len = qcdm_cmd_gsm_subsys_state_info_new ((char *) cmd->data, 50);
g_assert (cmd->len); g_assert (cmd->len);
mm_qcdm_serial_port_queue_command (port, mm_qcdm_serial_port_queue_command (ctx->port,
cmd, cmd,
3, 3,
NULL, NULL,
(MMQcdmSerialResponseFn) access_tech_qcdm_gsm_ready, (MMQcdmSerialResponseFn) access_tech_qcdm_gsm_ready,
ctx); ctx);
} else if (mm_iface_modem_is_cdma (self)) { } else if (mm_iface_modem_is_cdma (self)) {
cmd = g_byte_array_sized_new (50); /* If we don't have a QCDM port but the modem is CDMA-only, then
cmd->len = qcdm_cmd_cm_subsys_state_info_new ((char *) cmd->data, 50); * guess access technologies from the registration information.
g_assert (cmd->len); */
if (!ctx->port)
access_tech_from_cdma_registration_state (MM_BROADBAND_MODEM (self), ctx);
else {
cmd = g_byte_array_sized_new (50);
cmd->len = qcdm_cmd_cm_subsys_state_info_new ((char *) cmd->data, 50);
g_assert (cmd->len);
mm_qcdm_serial_port_queue_command (port, mm_qcdm_serial_port_queue_command (ctx->port,
cmd, cmd,
3, 3,
NULL, NULL,
(MMQcdmSerialResponseFn) access_tech_qcdm_cdma_ready, (MMQcdmSerialResponseFn) access_tech_qcdm_cdma_ready,
ctx); ctx);
}
} else } else
g_assert_not_reached (); g_assert_not_reached ();
} }

View File

@@ -868,23 +868,6 @@ registration_check_step (RunRegistrationChecksContext *ctx)
mm_iface_modem_cdma_update_evdo_registration_state (ctx->self, mm_iface_modem_cdma_update_evdo_registration_state (ctx->self,
ctx->evdo_state); ctx->evdo_state);
/* Update access technologies.
* TODO: proper EV-DO revision reporting */
{
MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
if (ctx->cdma1x_state == MM_MODEM_CDMA_REGISTRATION_STATE_HOME ||
ctx->cdma1x_state == MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING ||
ctx->cdma1x_state == MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED)
act |= MM_IFACE_MODEM_CDMA_ALL_CDMA1X_ACCESS_TECHNOLOGIES_MASK;
if (ctx->evdo_state == MM_MODEM_CDMA_REGISTRATION_STATE_HOME ||
ctx->evdo_state == MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING ||
ctx->evdo_state == MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED)
act |= MM_IFACE_MODEM_CDMA_ALL_EVDO_ACCESS_TECHNOLOGIES_MASK;
mm_iface_modem_cdma_update_access_technologies (MM_IFACE_MODEM_CDMA (ctx->self), act);
}
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
run_registration_checks_context_complete_and_free (ctx); run_registration_checks_context_complete_and_free (ctx);
return; return;