broadband-modem-novatel: read HDR revision for access technology
Specialize what the superclass gave us, if we can.
This commit is contained in:
@@ -305,6 +305,151 @@ set_allowed_modes (MMIfaceModem *self,
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Load access technologies (Modem interface) */
|
/* Load access technologies (Modem interface) */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
guint hdr_revision; /* QCDM_HDR_REV_x */
|
||||||
|
MMModemAccessTechnology generic_act;
|
||||||
|
guint mask;
|
||||||
|
} SnapshotResult;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MMBaseModem *self;
|
||||||
|
MMQcdmSerialPort *port;
|
||||||
|
GSimpleAsyncResult *simple;
|
||||||
|
MMModemAccessTechnology generic_act;
|
||||||
|
guint mask;
|
||||||
|
} SnapshotContext;
|
||||||
|
|
||||||
|
static void
|
||||||
|
snapshot_result_complete (GSimpleAsyncResult *simple,
|
||||||
|
guint hdr_revision,
|
||||||
|
MMModemAccessTechnology generic_act,
|
||||||
|
guint mask)
|
||||||
|
{
|
||||||
|
SnapshotResult *r;
|
||||||
|
|
||||||
|
r = g_new0 (SnapshotResult, 1);
|
||||||
|
r->hdr_revision = hdr_revision;
|
||||||
|
r->generic_act = generic_act;
|
||||||
|
r->mask = mask;
|
||||||
|
|
||||||
|
g_simple_async_result_set_op_res_gpointer (simple, r, g_free);
|
||||||
|
g_simple_async_result_complete (simple);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
snapshot_result_complete_simple (GSimpleAsyncResult *simple,
|
||||||
|
MMModemAccessTechnology generic_act,
|
||||||
|
guint mask)
|
||||||
|
{
|
||||||
|
snapshot_result_complete (simple, QCDM_HDR_REV_UNKNOWN, generic_act, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
snapshot_context_complete_and_free (SnapshotContext *ctx, guint hdr_revision)
|
||||||
|
{
|
||||||
|
snapshot_result_complete (ctx->simple,
|
||||||
|
hdr_revision,
|
||||||
|
ctx->generic_act,
|
||||||
|
ctx->mask);
|
||||||
|
g_object_unref (ctx->simple);
|
||||||
|
g_object_unref (ctx->self);
|
||||||
|
g_object_unref (ctx->port);
|
||||||
|
g_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nw_snapshot_old_cb (MMQcdmSerialPort *port,
|
||||||
|
GByteArray *response,
|
||||||
|
GError *error,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
SnapshotContext *ctx = user_data;
|
||||||
|
QcdmResult *result;
|
||||||
|
guint8 hdr_revision = QCDM_HDR_REV_UNKNOWN;
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
/* Just ignore the error and complete with the input info */
|
||||||
|
mm_dbg ("Couldn't run QCDM Novatel Modem MSM6500 snapshot: '%s'", error->message);
|
||||||
|
snapshot_context_complete_and_free (ctx, QCDM_HDR_REV_UNKNOWN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the response */
|
||||||
|
result = qcdm_cmd_nw_subsys_modem_snapshot_cdma_result ((const gchar *) response->data, response->len, NULL);
|
||||||
|
if (result) {
|
||||||
|
qcdm_result_get_u8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_HDR_REV, &hdr_revision);
|
||||||
|
qcdm_result_unref (result);
|
||||||
|
} else
|
||||||
|
mm_dbg ("Failed to get QCDM Novatel Modem MSM6500 snapshot.");
|
||||||
|
|
||||||
|
snapshot_context_complete_and_free (ctx, hdr_revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nw_snapshot_new_cb (MMQcdmSerialPort *port,
|
||||||
|
GByteArray *response,
|
||||||
|
GError *error,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
SnapshotContext *ctx = user_data;
|
||||||
|
QcdmResult *result;
|
||||||
|
GByteArray *nwsnap;
|
||||||
|
guint8 hdr_revision = QCDM_HDR_REV_UNKNOWN;
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
mm_dbg ("Couldn't run QCDM Novatel Modem MSM6800 snapshot: '%s'", error->message);
|
||||||
|
snapshot_context_complete_and_free (ctx, QCDM_HDR_REV_UNKNOWN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the response */
|
||||||
|
result = qcdm_cmd_nw_subsys_modem_snapshot_cdma_result ((const gchar *) response->data, response->len, NULL);
|
||||||
|
if (result) {
|
||||||
|
qcdm_result_get_u8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_HDR_REV, &hdr_revision);
|
||||||
|
qcdm_result_unref (result);
|
||||||
|
snapshot_context_complete_and_free (ctx, hdr_revision);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_dbg ("Failed to get QCDM Novatel Modem MSM6800 snapshot.");
|
||||||
|
|
||||||
|
/* Try for MSM6500 */
|
||||||
|
nwsnap = g_byte_array_sized_new (25);
|
||||||
|
nwsnap->len = qcdm_cmd_nw_subsys_modem_snapshot_cdma_new ((char *) nwsnap->data, 25, QCDM_NW_CHIPSET_6500);
|
||||||
|
g_assert (nwsnap->len);
|
||||||
|
mm_qcdm_serial_port_queue_command (port, nwsnap, 3, NULL, nw_snapshot_old_cb, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
get_nw_modem_snapshot (MMBaseModem *self,
|
||||||
|
GSimpleAsyncResult *simple,
|
||||||
|
MMModemAccessTechnology generic_act,
|
||||||
|
guint mask)
|
||||||
|
{
|
||||||
|
SnapshotContext *ctx;
|
||||||
|
GByteArray *nwsnap;
|
||||||
|
MMQcdmSerialPort *port;
|
||||||
|
|
||||||
|
port = mm_base_modem_peek_port_qcdm (self);
|
||||||
|
if (!port)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Setup context */
|
||||||
|
ctx = g_new0 (SnapshotContext, 1);
|
||||||
|
ctx->self = g_object_ref (self);
|
||||||
|
ctx->port = g_object_ref (port);
|
||||||
|
ctx->simple = simple;
|
||||||
|
ctx->generic_act = generic_act;
|
||||||
|
ctx->mask = mask;
|
||||||
|
|
||||||
|
/* Try MSM6800 first since newer cards use that */
|
||||||
|
nwsnap = g_byte_array_sized_new (25);
|
||||||
|
nwsnap->len = qcdm_cmd_nw_subsys_modem_snapshot_cdma_new ((char *) nwsnap->data, 25, QCDM_NW_CHIPSET_6800);
|
||||||
|
g_assert (nwsnap->len);
|
||||||
|
mm_qcdm_serial_port_queue_command (port, nwsnap, 3, NULL, nw_snapshot_new_cb, ctx);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
modem_load_access_technologies_finish (MMIfaceModem *self,
|
modem_load_access_technologies_finish (MMIfaceModem *self,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
@@ -312,12 +457,31 @@ modem_load_access_technologies_finish (MMIfaceModem *self,
|
|||||||
guint *mask,
|
guint *mask,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
|
SnapshotResult *r;
|
||||||
|
MMModemAccessTechnology act;
|
||||||
|
|
||||||
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
|
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* Remember we're only giving 3GPP access technologies */
|
r = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
|
||||||
*access_technologies = GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
|
|
||||||
*mask = MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK;
|
act = r->generic_act;
|
||||||
|
if (act & MM_IFACE_MODEM_CDMA_ALL_EVDO_ACCESS_TECHNOLOGIES_MASK) {
|
||||||
|
/* Update access technology with specific EVDO revision from QCDM */
|
||||||
|
if (r->hdr_revision == QCDM_HDR_REV_0) {
|
||||||
|
mm_dbg ("Novatel Modem Snapshot EVDO revision: 0");
|
||||||
|
act &= ~MM_IFACE_MODEM_CDMA_ALL_EVDO_ACCESS_TECHNOLOGIES_MASK;
|
||||||
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_EVDO0;
|
||||||
|
} else if (r->hdr_revision == QCDM_HDR_REV_A) {
|
||||||
|
mm_dbg ("Novatel Modem Snapshot EVDO revision: A");
|
||||||
|
act &= ~MM_IFACE_MODEM_CDMA_ALL_EVDO_ACCESS_TECHNOLOGIES_MASK;
|
||||||
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_EVDOA;
|
||||||
|
} else
|
||||||
|
mm_dbg ("Novatel Modem Snapshot EVDO revision: %d (unknown)", r->hdr_revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
*access_technologies = act;
|
||||||
|
*mask = r->mask;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,22 +504,59 @@ cnti_set_ready (MMBaseModem *self,
|
|||||||
|
|
||||||
p = mm_strip_tag (response, "$CNTI:");
|
p = mm_strip_tag (response, "$CNTI:");
|
||||||
p = strchr (p, ',');
|
p = strchr (p, ',');
|
||||||
if (p) {
|
if (!p) {
|
||||||
g_simple_async_result_set_op_res_gpointer (
|
error = g_error_new (MM_CORE_ERROR,
|
||||||
simple,
|
MM_CORE_ERROR_FAILED,
|
||||||
GUINT_TO_POINTER (mm_string_to_access_tech (p)),
|
"Couldn't parse $CNTI result '%s'",
|
||||||
NULL);
|
response);
|
||||||
} else {
|
g_simple_async_result_take_error (simple, error);
|
||||||
g_simple_async_result_set_error (
|
g_simple_async_result_complete (simple);
|
||||||
simple,
|
g_object_unref (simple);
|
||||||
MM_CORE_ERROR,
|
return;
|
||||||
MM_CORE_ERROR_FAILED,
|
|
||||||
"Couldn't parse $CNTI result '%s'",
|
|
||||||
response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_simple_async_result_complete (simple);
|
snapshot_result_complete_simple (simple,
|
||||||
g_object_unref (simple);
|
mm_string_to_access_tech (p),
|
||||||
|
MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parent_load_access_technologies_ready (MMIfaceModem *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GSimpleAsyncResult *simple)
|
||||||
|
{
|
||||||
|
MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
|
||||||
|
guint mask = 0;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!iface_modem_parent->load_access_technologies_finish (self,
|
||||||
|
res,
|
||||||
|
&act,
|
||||||
|
&mask,
|
||||||
|
&error)) {
|
||||||
|
g_simple_async_result_take_error (simple, error);
|
||||||
|
g_simple_async_result_complete (simple);
|
||||||
|
g_object_unref (simple);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No point in checking EVDO revision if EVDO isn't being used or if for
|
||||||
|
* some reason we don't have a QCDM port.
|
||||||
|
*/
|
||||||
|
if (!(act & MM_IFACE_MODEM_CDMA_ALL_EVDO_ACCESS_TECHNOLOGIES_MASK)) {
|
||||||
|
snapshot_result_complete (simple, QCDM_HDR_REV_UNKNOWN, act, mask);
|
||||||
|
g_object_unref (simple);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pass along the access tech & mask that the parent determined so we
|
||||||
|
* can specialize it based on the EVDO revision from QCDM.
|
||||||
|
*/
|
||||||
|
if (!get_nw_modem_snapshot (MM_BASE_MODEM (self), simple, act, mask)) {
|
||||||
|
/* If there's any error, use the access tech that the parent interface determined */
|
||||||
|
snapshot_result_complete (simple, QCDM_HDR_REV_UNKNOWN, act, mask);
|
||||||
|
g_object_unref (simple);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -370,15 +571,15 @@ modem_load_access_technologies (MMIfaceModem *self,
|
|||||||
user_data,
|
user_data,
|
||||||
modem_load_access_technologies);
|
modem_load_access_technologies);
|
||||||
|
|
||||||
/* Load access technologies only in 3GPP modems */
|
/* CDMA-only modems defer to parent for generic access technology
|
||||||
if (!mm_iface_modem_is_3gpp (self)) {
|
* checking, but can determine EVDOr0 vs. EVDOrA through proprietary
|
||||||
g_simple_async_result_set_error (
|
* QCDM commands.
|
||||||
result,
|
*/
|
||||||
MM_CORE_ERROR,
|
if (mm_iface_modem_is_cdma_only (self)) {
|
||||||
MM_CORE_ERROR_UNSUPPORTED,
|
iface_modem_parent->load_access_technologies (
|
||||||
"Loading access technologies not supported in CDMA-only modems");
|
self,
|
||||||
g_simple_async_result_complete_in_idle (result);
|
(GAsyncReadyCallback)parent_load_access_technologies_ready,
|
||||||
g_object_unref (result);
|
result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user