aboutsummaryrefslogtreecommitdiff
path: root/plugins/icera/mm-iface-icera.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/icera/mm-iface-icera.c')
-rw-r--r--plugins/icera/mm-iface-icera.c311
1 files changed, 231 insertions, 80 deletions
diff --git a/plugins/icera/mm-iface-icera.c b/plugins/icera/mm-iface-icera.c
index 89862b23..e530d79c 100644
--- a/plugins/icera/mm-iface-icera.c
+++ b/plugins/icera/mm-iface-icera.c
@@ -733,36 +733,119 @@ mm_iface_icera_modem_load_unlock_retries (MMIfaceModem *self,
}
/*****************************************************************************/
-/* Load supported bands (Modem interface) */
+/* Generic band handling utilities */
typedef struct {
MMModemBand band;
- const char *name;
-} BandTable;
+ char *name;
+ gboolean enabled;
+} Band;
+
+static void
+band_free (Band *b)
+{
+ g_free (b->name);
+ g_free (b);
+}
-static BandTable modem_bands[] = {
+static const Band modem_bands[] = {
/* Sort 3G first since it's preferred */
- { MM_MODEM_BAND_U2100, "FDD_BAND_I" },
- { MM_MODEM_BAND_U1900, "FDD_BAND_II" },
- /*
- * Several bands are forbidden to set and will always read as
- * disabled, so we won't present them to the rest of
- * modemmanager.
- */
- /* { MM_MODEM_BAND_U1800, "FDD_BAND_III" }, */
- /* { MM_MODEM_BAND_U17IV, "FDD_BAND_IV" }, */
- /* { MM_MODEM_BAND_U800, "FDD_BAND_VI" }, */
- { MM_MODEM_BAND_U850, "FDD_BAND_V" },
- { MM_MODEM_BAND_U900, "FDD_BAND_VIII" },
- { MM_MODEM_BAND_G850, "G850" },
+ { MM_MODEM_BAND_U2100, "FDD_BAND_I", FALSE },
+ { MM_MODEM_BAND_U1900, "FDD_BAND_II", FALSE },
+ { MM_MODEM_BAND_U1800, "FDD_BAND_III", FALSE },
+ { MM_MODEM_BAND_U17IV, "FDD_BAND_IV", FALSE },
+ { MM_MODEM_BAND_U800, "FDD_BAND_VI", FALSE },
+ { MM_MODEM_BAND_U850, "FDD_BAND_V", FALSE },
+ { MM_MODEM_BAND_U900, "FDD_BAND_VIII", FALSE },
/* 2G second */
- { MM_MODEM_BAND_DCS, "DCS" },
- { MM_MODEM_BAND_EGSM, "EGSM" },
- { MM_MODEM_BAND_PCS, "PCS" },
+ { MM_MODEM_BAND_G850, "G850", FALSE },
+ { MM_MODEM_BAND_DCS, "DCS", FALSE },
+ { MM_MODEM_BAND_EGSM, "EGSM", FALSE },
+ { MM_MODEM_BAND_PCS, "PCS", FALSE },
/* And ANY last since it's most inclusive */
- { MM_MODEM_BAND_ANY, "ANY" },
+ { MM_MODEM_BAND_ANY, "ANY", FALSE },
};
+static MMModemBand
+icera_band_to_mm (const char *icera)
+{
+ int i;
+
+ for (i = 0 ; i < G_N_ELEMENTS (modem_bands); i++) {
+ if (g_strcmp0 (icera, modem_bands[i].name) == 0)
+ return modem_bands[i].band;
+ }
+ return MM_MODEM_BAND_UNKNOWN;
+}
+
+static GSList *
+parse_bands (const gchar *response, guint32 *out_len)
+{
+ GRegex *r;
+ GMatchInfo *info;
+ GSList *bands = NULL;
+
+ g_return_val_if_fail (out_len != NULL, NULL);
+
+ /*
+ * Response is a number of lines of the form:
+ * "EGSM": 0
+ * "FDD_BAND_I": 1
+ * ...
+ * with 1 and 0 indicating whether the particular band is enabled or not.
+ */
+ r = g_regex_new ("^\"(\\w+)\": (\\d)",
+ G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_ANY,
+ NULL);
+ g_assert (r != NULL);
+
+ g_regex_match (r, response, 0, &info);
+ while (g_match_info_matches (info)) {
+ gchar *name, *enabled;
+ Band *b;
+ MMModemBand band;
+
+ name = g_match_info_fetch (info, 1);
+ enabled = g_match_info_fetch (info, 2);
+ band = icera_band_to_mm (name);
+ if (band != MM_MODEM_BAND_UNKNOWN) {
+ b = g_malloc0 (sizeof (Band));
+ b->band = band;
+ b->name = g_strdup (name);
+ b->enabled = (enabled[0] == '1' ? TRUE : FALSE);
+ bands = g_slist_append (bands, b);
+ *out_len = *out_len + 1;
+ }
+ g_free (name);
+ g_free (enabled);
+ g_match_info_next (info, NULL);
+ }
+ g_match_info_free (info);
+ g_regex_unref (r);
+
+ return bands;
+}
+
+/*****************************************************************************/
+/* Load supported bands (Modem interface) */
+
+typedef struct {
+ MMBaseModemAtCommand *cmds;
+ GSList *bands;
+ guint32 idx;
+} SupportedBandsContext;
+
+static void
+supported_bands_context_free (SupportedBandsContext *ctx)
+{
+ guint i;
+
+ for (i = 0; ctx->cmds[i].command; i++)
+ g_free (ctx->cmds[i].command);
+ g_free (ctx->cmds);
+ g_slist_free_full (ctx->bands, (GDestroyNotify) band_free);
+ g_free (ctx);
+}
GArray *
mm_iface_icera_modem_load_supported_bands_finish (MMIfaceModem *self,
@@ -774,35 +857,131 @@ mm_iface_icera_modem_load_supported_bands_finish (MMIfaceModem *self,
G_SIMPLE_ASYNC_RESULT (res)));
}
+static void
+load_supported_bands_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GSimpleAsyncResult *simple)
+{
+ GError *error = NULL;
+ SupportedBandsContext *ctx = NULL;
+ GArray *bands;
+ GSList *iter;
+
+ mm_base_modem_at_sequence_finish (self, res, (gpointer) &ctx, &error);
+ if (error)
+ g_simple_async_result_take_error (simple, error);
+ else {
+ bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), ctx->idx);
+ for (iter = ctx->bands; iter; iter = g_slist_next (iter)) {
+ Band *b = iter->data;
+
+ /* 'enabled' here really means supported/unsupported */
+ if (b->enabled)
+ g_array_append_val (bands, b->band);
+ }
+
+ g_simple_async_result_set_op_res_gpointer (simple,
+ bands,
+ (GDestroyNotify) g_array_unref);
+ }
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static gboolean
+load_supported_bands_response_processor (MMBaseModem *self,
+ gpointer context,
+ const gchar *command,
+ const gchar *response,
+ gboolean last_command,
+ const GError *error,
+ GVariant **result,
+ GError **result_error)
+{
+ SupportedBandsContext *ctx = context;
+ Band *b = g_slist_nth_data (ctx->bands, ctx->idx++);
+
+ /* If there was no error setting the band, that band is supported. We
+ * abuse the 'enabled' item to mean supported/unsupported.
+ */
+ b->enabled = !error;
+
+ /* Continue to next band */
+ return FALSE;
+}
+
+static void
+load_supported_bands_get_bands_ready (MMIfaceModem *self,
+ GAsyncResult *res,
+ GSimpleAsyncResult *operation_result)
+{
+ SupportedBandsContext *ctx;
+ const gchar *response;
+ GError *error;
+ GSList *iter;
+ guint32 len = 0, i;
+
+ response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
+ if (!response) {
+ mm_dbg ("Couldn't query current bands: '%s'", error->message);
+ g_simple_async_result_take_error (operation_result, error);
+ g_simple_async_result_complete (operation_result);
+ g_object_unref (operation_result);
+ return;
+ }
+
+ ctx = g_new0 (SupportedBandsContext, 1);
+
+ /* For each reported band, build up an AT command to set that band
+ * to its current enabled/disabled state.
+ */
+ ctx->bands = parse_bands (response, &len);
+ ctx->cmds = g_new0 (MMBaseModemAtCommand, len + 1);
+
+ for (iter = ctx->bands, i = 0; iter; iter = g_slist_next (iter), i++) {
+ Band *b = iter->data;
+
+ ctx->cmds[i].command = g_strdup_printf ("%%IPBM=\"%s\",%c",
+ b->name,
+ b->enabled ? '1' : '0');
+ ctx->cmds[i].timeout = 3;
+ ctx->cmds[i].allow_cached = FALSE;
+ ctx->cmds[i].response_processor = load_supported_bands_response_processor;
+ }
+
+ mm_base_modem_at_sequence (MM_BASE_MODEM (self),
+ ctx->cmds,
+ ctx,
+ (GDestroyNotify) supported_bands_context_free,
+ (GAsyncReadyCallback) load_supported_bands_ready,
+ operation_result);
+}
+
void
mm_iface_icera_modem_load_supported_bands (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *result;
- GArray *bands;
- guint i;
result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
mm_iface_icera_modem_load_supported_bands);
- /*
- * The modem doesn't support telling us what bands are supported;
- * list everything we know about.
+ /* The modems report some bands as disabled that they don't actually
+ * support enabling. Thanks Icera! So we have to try setting each
+ * band to it's current enabled/disabled value, and the modem will
+ * return an error if it doesn't support that band at all.
*/
- bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), G_N_ELEMENTS (modem_bands));
- for (i = 0 ; i < G_N_ELEMENTS (modem_bands) ; i++) {
- if (modem_bands[i].band != MM_MODEM_BAND_ANY)
- g_array_append_val(bands, modem_bands[i].band);
- }
- g_simple_async_result_set_op_res_gpointer (result,
- bands,
- (GDestroyNotify)g_array_unref);
- g_simple_async_result_complete_in_idle (result);
- g_object_unref (result);
+ mm_base_modem_at_command (
+ MM_BASE_MODEM (self),
+ "%IPBM?",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback)load_supported_bands_get_bands_ready,
+ result);
}
/*****************************************************************************/
@@ -824,11 +1003,11 @@ load_current_bands_ready (MMIfaceModem *self,
GAsyncResult *res,
GSimpleAsyncResult *operation_result)
{
- GRegex *r;
- GMatchInfo *info;
GArray *bands;
const gchar *response;
GError *error;
+ GSList *parsed, *iter;
+ guint32 len = 0;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
if (!response) {
@@ -836,51 +1015,23 @@ load_current_bands_ready (MMIfaceModem *self,
g_simple_async_result_take_error (operation_result, error);
g_simple_async_result_complete (operation_result);
g_object_unref (operation_result);
- return;
- }
-
- /*
- * Response is a number of lines of the form:
- * "EGSM": 0
- * "FDD_BAND_I": 1
- * ...
- * with 1 and 0 indicating whether the particular band is enabled or not.
- */
- r = g_regex_new ("^\"(\\w+)\": (\\d)",
- G_REGEX_MULTILINE, G_REGEX_MATCH_NEWLINE_ANY,
- NULL);
- g_assert (r != NULL);
-
- bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand),
- G_N_ELEMENTS (modem_bands));
-
- g_regex_match (r, response, 0, &info);
- while (g_match_info_matches (info)) {
- gchar *band, *enabled;
+ } else {
+ /* Parse bands from Icera response into MM band numbers */
+ parsed = parse_bands (response, &len);
+ bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), len);
+ for (iter = parsed; iter; iter = g_slist_next (iter)) {
+ Band *b = iter->data;
- band = g_match_info_fetch (info, 1);
- enabled = g_match_info_fetch (info, 2);
- if (enabled[0] == '1') {
- guint i;
- for (i = 0 ; i < G_N_ELEMENTS (modem_bands); i++) {
- if (!strcmp (band, modem_bands[i].name)) {
- g_array_append_val (bands, modem_bands[i].band);
- break;
- }
- }
+ g_array_append_val (bands, b->band);
}
- g_free (band);
- g_free (enabled);
- g_match_info_next (info, NULL);
- }
- g_match_info_free (info);
- g_regex_unref (r);
+ g_slist_free_full (parsed, (GDestroyNotify) band_free);
- g_simple_async_result_set_op_res_gpointer (operation_result,
- bands,
- (GDestroyNotify)g_array_unref);
- g_simple_async_result_complete (operation_result);
- g_object_unref (operation_result);
+ g_simple_async_result_set_op_res_gpointer (operation_result,
+ bands,
+ (GDestroyNotify)g_array_unref);
+ g_simple_async_result_complete (operation_result);
+ g_object_unref (operation_result);
+ }
}
void