diff options
Diffstat (limited to 'plugins/mm-modem-novatel-cdma.c')
-rw-r--r-- | plugins/mm-modem-novatel-cdma.c | 148 |
1 files changed, 139 insertions, 9 deletions
diff --git a/plugins/mm-modem-novatel-cdma.c b/plugins/mm-modem-novatel-cdma.c index 64ee15f..6b8c4aa 100644 --- a/plugins/mm-modem-novatel-cdma.c +++ b/plugins/mm-modem-novatel-cdma.c @@ -21,6 +21,8 @@ #include <ctype.h> #include "mm-modem-novatel-cdma.h" +#include "mm-modem-helpers.h" +#include "libqcdm/src/commands.h" #include "mm-errors.h" #include "mm-callback-info.h" @@ -35,7 +37,9 @@ mm_modem_novatel_cdma_new (const char *device, const char *driver, const char *plugin, gboolean evdo_rev0, - gboolean evdo_revA) + gboolean evdo_revA, + guint32 vendor, + guint32 product) { g_return_val_if_fail (device != NULL, NULL); g_return_val_if_fail (driver != NULL, NULL); @@ -72,6 +76,8 @@ get_one_qual (const char *reply, const char *tag) { int qual = -1; const char *p; + long int dbm; + gboolean success = FALSE; p = strstr (reply, tag); if (!p) @@ -83,17 +89,26 @@ get_one_qual (const char *reply, const char *tag) /* Skip spaces */ while (isspace (*p)) p++; - if (*p == '-') { - long int dbm; - - errno = 0; - dbm = strtol (p, NULL, 10); - if (dbm < 0 && errno == 0) { - dbm = CLAMP (dbm, -113, -51); - qual = 100 - ((dbm + 51) * 100 / (-113 + 51)); + + errno = 0; + dbm = strtol (p, NULL, 10); + if (errno == 0) { + if (*p == '-') { + /* Some cards appear to use RX0/RX1 and output RSSI in negative dBm */ + if (dbm < 0) + success = TRUE; + } else if (isdigit (*p) && (dbm > 0) && (dbm < 115)) { + /* S720 appears to use "1x RSSI" and print RSSI in dBm without '-' */ + dbm *= -1; + success = TRUE; } } + if (success) { + dbm = CLAMP (dbm, -113, -51); + qual = 100 - ((dbm + 51) * 100 / (-113 + 51)); + } + return qual; } @@ -123,6 +138,8 @@ get_rssi_done (MMAtSerialPort *port, /* Parse the signal quality */ qual = get_one_qual (response->str, "RX0="); if (qual < 0) + qual = get_one_qual (response->str, "1x RSSI="); + if (qual < 0) qual = get_one_qual (response->str, "RX1="); if (qual >= 0) { @@ -165,6 +182,115 @@ get_signal_quality (MMModemCdma *modem, /*****************************************************************************/ static void +parse_modem_snapshot (MMCallbackInfo *info, QCDMResult *result) +{ + MMModemCdmaRegistrationState evdo_state, cdma1x_state, new_state; + guint8 eri = 0; + + g_return_if_fail (info != NULL); + g_return_if_fail (result != NULL); + + evdo_state = mm_generic_cdma_query_reg_state_get_callback_evdo_state (info); + cdma1x_state = mm_generic_cdma_query_reg_state_get_callback_1x_state (info); + + /* Roaming? */ + if (qcdm_result_get_uint8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_ERI, &eri)) { + char *str; + gboolean roaming = FALSE; + + str = g_strdup_printf ("%u", eri); + if (mm_cdma_parse_eri (str, &roaming, NULL, NULL)) { + new_state = roaming ? MM_MODEM_CDMA_REGISTRATION_STATE_HOME : MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING; + if (cdma1x_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) + mm_generic_cdma_query_reg_state_set_callback_1x_state (info, new_state); + if (evdo_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) + mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, new_state); + } + g_free (str); + } +} + +static void +reg_nwsnap_6500_cb (MMQcdmSerialPort *port, + GByteArray *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + QCDMResult *result; + + if (!error) { + result = qcdm_cmd_nw_subsys_modem_snapshot_cdma_result ((const char *) response->data, response->len, NULL); + if (result) { + parse_modem_snapshot (info, result); + qcdm_result_unref (result); + } + } + mm_callback_info_schedule (info); +} + +static void +reg_nwsnap_6800_cb (MMQcdmSerialPort *port, + GByteArray *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + QCDMResult *result; + GByteArray *nwsnap; + + if (error) + goto done; + + /* Parse the response */ + result = qcdm_cmd_nw_subsys_modem_snapshot_cdma_result ((const char *) response->data, response->len, &info->error); + if (!result) { + g_clear_error (&info->error); + + /* 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, NULL); + g_assert (nwsnap->len); + mm_qcdm_serial_port_queue_command (port, nwsnap, 3, reg_nwsnap_6500_cb, info); + return; + } + + parse_modem_snapshot (info, result); + qcdm_result_unref (result); + +done: + mm_callback_info_schedule (info); +} + +static void +query_registration_state (MMGenericCdma *cdma, + MMModemCdmaRegistrationState cur_cdma_state, + MMModemCdmaRegistrationState cur_evdo_state, + MMModemCdmaRegistrationStateFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + MMQcdmSerialPort *port; + GByteArray *nwsnap; + + info = mm_generic_cdma_query_reg_state_callback_info_new (cdma, cur_cdma_state, cur_evdo_state, callback, user_data); + + port = mm_generic_cdma_get_best_qcdm_port (cdma, &info->error); + if (!port) { + mm_callback_info_schedule (info); + return; + } + + /* 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, NULL); + g_assert (nwsnap->len); + mm_qcdm_serial_port_queue_command (port, nwsnap, 3, reg_nwsnap_6800_cb, info); +} + +/*****************************************************************************/ + +static void modem_cdma_init (MMModemCdma *cdma_class) { cdma_class->get_signal_quality = get_signal_quality; @@ -178,6 +304,10 @@ mm_modem_novatel_cdma_init (MMModemNovatelCdma *self) static void mm_modem_novatel_cdma_class_init (MMModemNovatelCdmaClass *klass) { + MMGenericCdmaClass *generic_class = MM_GENERIC_CDMA_CLASS (klass); + mm_modem_novatel_cdma_parent_class = g_type_class_peek_parent (klass); + + generic_class->query_registration_state = query_registration_state; } |