aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2012-07-27 19:56:25 -0500
committerDan Williams <dcbw@redhat.com>2012-08-03 10:53:14 -0500
commit48466e31ca2ef9301637761d67249d52b3d6a3ec (patch)
tree0de49bbea4e7aa5f0c33ee40f0a4096f6f6b1651
parent9dfe54399e9faa81cc6ce2002c9f13252d6c6685 (diff)
icera/samsung: implement supported bands
-rw-r--r--plugins/mm-modem-icera.c264
-rw-r--r--plugins/mm-modem-icera.h10
-rwxr-xr-xplugins/mm-modem-samsung-gsm.c12
3 files changed, 219 insertions, 67 deletions
diff --git a/plugins/mm-modem-icera.c b/plugins/mm-modem-icera.c
index cdb7ef82..4256a486 100644
--- a/plugins/mm-modem-icera.c
+++ b/plugins/mm-modem-icera.c
@@ -825,34 +825,50 @@ mm_modem_icera_get_local_timestamp (MMModemIcera *self,
typedef struct {
MMModemGsmBand band;
- const char *name;
-} BandTable;
+ char *name;
+ gboolean enabled;
+ gpointer data;
+} Band;
-static BandTable modem_bands[] = {
+static void
+band_free (Band *b)
+{
+ g_free (b->name);
+ g_free (b);
+}
+
+static const Band modem_bands[] = {
/* Sort 3G first since it's preferred */
- { MM_MODEM_GSM_BAND_U2100, "FDD_BAND_I" },
- { MM_MODEM_GSM_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_GSM_BAND_U1800, "FDD_BAND_III" }, */
- /* { MM_MODEM_GSM_BAND_U17IV, "FDD_BAND_IV" }, */
- /* { MM_MODEM_GSM_BAND_U800, "FDD_BAND_VI" }, */
- { MM_MODEM_GSM_BAND_U850, "FDD_BAND_V" },
- { MM_MODEM_GSM_BAND_U900, "FDD_BAND_VIII" },
- { MM_MODEM_GSM_BAND_G850, "G850" },
+ { MM_MODEM_GSM_BAND_U2100, "FDD_BAND_I", FALSE, NULL },
+ { MM_MODEM_GSM_BAND_U1900, "FDD_BAND_II", FALSE, NULL },
+ { MM_MODEM_GSM_BAND_U1800, "FDD_BAND_III", FALSE, NULL },
+ { MM_MODEM_GSM_BAND_U17IV, "FDD_BAND_IV", FALSE, NULL },
+ { MM_MODEM_GSM_BAND_U800, "FDD_BAND_VI", FALSE, NULL },
+ { MM_MODEM_GSM_BAND_U850, "FDD_BAND_V", FALSE, NULL },
+ { MM_MODEM_GSM_BAND_U900, "FDD_BAND_VIII", FALSE, NULL },
/* 2G second */
- { MM_MODEM_GSM_BAND_DCS, "DCS" },
- { MM_MODEM_GSM_BAND_EGSM, "EGSM" },
- { MM_MODEM_GSM_BAND_PCS, "PCS" },
+ { MM_MODEM_GSM_BAND_G850, "G850", FALSE, NULL },
+ { MM_MODEM_GSM_BAND_DCS, "DCS", FALSE, NULL },
+ { MM_MODEM_GSM_BAND_EGSM, "EGSM", FALSE, NULL },
+ { MM_MODEM_GSM_BAND_PCS, "PCS", FALSE, NULL },
/* And ANY last since it's most inclusive */
- { MM_MODEM_GSM_BAND_ANY, "ANY" },
+ { MM_MODEM_GSM_BAND_ANY, "ANY", FALSE, NULL },
};
+static MMModemGsmBand
+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_GSM_BAND_UNKNOWN;
+}
+
static const char *
-band_mm_to_icera (MMModemGsmBand band)
+mm_band_to_icera (MMModemGsmBand band)
{
int i;
@@ -863,21 +879,19 @@ band_mm_to_icera (MMModemGsmBand band)
return NULL;
}
-
-static gboolean
-parse_ipbm (const char *reply, MMModemGsmBand *band)
+/* returns a list of 'Band' structs */
+static GSList *
+build_bands_info (const gchar *response, gboolean build_command)
{
+ GSList *bands = NULL;
GRegex *r;
- GMatchInfo *info;
-
- g_return_val_if_fail (band != NULL, FALSE);
- g_return_val_if_fail (reply != NULL, FALSE);
+ GMatchInfo *match;
/*
* Response is a number of lines of the form:
- * "EGSM": 0
- * "FDD_BAND_I": 1
- * ...
+ * "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)",
@@ -885,57 +899,83 @@ parse_ipbm (const char *reply, MMModemGsmBand *band)
NULL);
g_assert (r != NULL);
- g_regex_match (r, reply, 0, &info);
- while (g_match_info_matches (info)) {
- gchar *b, *e;
-
- b = g_match_info_fetch (info, 1);
- e = g_match_info_fetch (info, 2);
- if (e[0] == '1') {
- guint i;
- for (i = 0 ; i < G_N_ELEMENTS (modem_bands); i++) {
- if (!strcmp (b, modem_bands[i].name)) {
- *band |= modem_bands[i].band;
- break;
- }
+ g_regex_match (r, response, 0, &match);
+ while (g_match_info_matches (match)) {
+ gchar *name, *enabled;
+ Band *b;
+ MMModemGsmBand band;
+
+ name = g_match_info_fetch (match, 1);
+ enabled = g_match_info_fetch (match, 2);
+ band = icera_band_to_mm (name);
+ if (band != MM_MODEM_GSM_BAND_UNKNOWN && band != MM_MODEM_GSM_BAND_ANY) {
+ b = g_malloc0 (sizeof (Band));
+ b->band = band;
+ b->enabled = (enabled[0] == '1' ? TRUE : FALSE);
+ if (build_command) {
+ /* abuse 'name' for the AT command to check band support */
+ b->name = g_strdup_printf ("%%IPBM=\"%s\",%c",
+ name,
+ b->enabled ? '1' : '0');
}
+ bands = g_slist_append (bands, b);
}
- g_free (b);
- g_free (e);
- g_match_info_next (info, NULL);
+ g_free (name);
+ g_free (enabled);
+ g_match_info_next (match, NULL);
}
- g_match_info_free (info);
+ g_match_info_free (match);
g_regex_unref (r);
- return (*band > 0 ? TRUE : FALSE);
+ return bands;
}
static void
-get_band_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
+get_current_bands_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMModemGsmBand mm_band = MM_MODEM_GSM_BAND_UNKNOWN;
+ MMModemGsmBand mm_band = MM_MODEM_GSM_BAND_ANY;
+ GSList *bands;
+ Band *b;
+ GSList *iter;
/* If the modem has already been removed, return without
* scheduling callback */
if (mm_callback_info_check_modem_removed (info))
return;
- if (error)
+ if (error) {
info->error = g_error_copy (error);
- else if (parse_ipbm (response->str, &mm_band))
- mm_callback_info_set_result (info, GUINT_TO_POINTER (mm_band), NULL);
+ mm_callback_info_schedule (info);
+ return;
+ }
+ bands = build_bands_info (response->str, FALSE);
+ if (!bands) {
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (MM_MODEM_GSM_BAND_UNKNOWN), NULL);
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ for (iter = bands; iter; iter = g_slist_next (iter)) {
+ b = iter->data;
+ if (b->enabled)
+ mm_band |= b->band;
+ }
+ g_slist_foreach (bands, (GFunc) band_free, NULL);
+ g_slist_free (bands);
+
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mm_band), NULL);
mm_callback_info_schedule (info);
}
void
-mm_modem_icera_get_band (MMModemIcera *self,
- MMModemUIntFn callback,
- gpointer user_data)
+mm_modem_icera_get_current_bands (MMModemIcera *self,
+ MMModemUIntFn callback,
+ gpointer user_data)
{
MMAtSerialPort *port;
MMCallbackInfo *info;
@@ -949,7 +989,105 @@ mm_modem_icera_get_band (MMModemIcera *self,
return;
}
- mm_at_serial_port_queue_command (port, "AT%IPBM?", 3, get_band_done, info);
+ mm_at_serial_port_queue_command (port, "AT%IPBM?", 3, get_current_bands_done, info);
+}
+
+#define NUM_BANDS_TAG "num-bands"
+#define BAND_RESULT_TAG "band-result"
+
+static void
+get_one_supported_band_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ Band *b = user_data;
+ MMCallbackInfo *info = b->data;
+ MMModemGsmBand mm_bands = MM_MODEM_GSM_BAND_UNKNOWN;
+ guint num;
+
+ if (mm_callback_info_check_modem_removed (info) == FALSE) {
+ /* Update supported bands list */
+ mm_bands = GPOINTER_TO_UINT (mm_callback_info_get_data (info, BAND_RESULT_TAG));
+ if (error == NULL) {
+ mm_bands |= b->band;
+ mm_callback_info_set_data (info, BAND_RESULT_TAG, GUINT_TO_POINTER (mm_bands), NULL);
+ }
+
+ num = GPOINTER_TO_UINT (mm_callback_info_get_data (info, NUM_BANDS_TAG)) - 1;
+ mm_callback_info_set_data (info, NUM_BANDS_TAG, GUINT_TO_POINTER (num), NULL);
+ if (num == 0) {
+ /* All done */
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mm_bands), NULL);
+ mm_callback_info_schedule (info);
+ }
+ }
+ band_free (b);
+}
+
+static void
+get_supported_bands_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ GSList *bands, *iter;
+ Band *b;
+ guint i;
+
+ /* If the modem has already been removed, return without
+ * scheduling callback */
+ if (mm_callback_info_check_modem_removed (info))
+ return;
+
+ if (error) {
+ info->error = g_error_copy (error);
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ bands = build_bands_info (response->str, TRUE);
+ if (!bands) {
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (MM_MODEM_GSM_BAND_UNKNOWN), NULL);
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ for (iter = bands, i = 0; iter; iter = g_slist_next (iter), i++) {
+ b = iter->data;
+ b->data = info;
+ mm_at_serial_port_queue_command (port, b->name, 10, get_one_supported_band_done, b);
+ }
+ /* Free list, but not items; they are freed when the AT response comes back */
+ g_slist_free (bands);
+
+ mm_callback_info_set_data (info, NUM_BANDS_TAG, GUINT_TO_POINTER (i), NULL);
+}
+
+void
+mm_modem_icera_get_supported_bands (MMModemIcera *self,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMAtSerialPort *port;
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data);
+
+ /* Otherwise ask the modem */
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ /* 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.
+ */
+ mm_at_serial_port_queue_command (port, "AT%IPBM?", 3, get_supported_bands_done, info);
}
static void
@@ -997,7 +1135,7 @@ mm_modem_icera_set_band (MMModemIcera *self,
return;
}
- icera_band = band_mm_to_icera (band);
+ icera_band = mm_band_to_icera (band);
if (!icera_band) {
info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Invalid band.");
mm_callback_info_schedule (info);
@@ -1005,7 +1143,7 @@ mm_modem_icera_set_band (MMModemIcera *self,
}
command = g_strdup_printf ("AT%%IPBM=\"%s\",1", icera_band);
- mm_at_serial_port_queue_command (port, command, 3, set_band_done, info);
+ mm_at_serial_port_queue_command (port, command, 10, set_band_done, info);
g_free (command);
}
diff --git a/plugins/mm-modem-icera.h b/plugins/mm-modem-icera.h
index ed6bf63b..9a974c5e 100644
--- a/plugins/mm-modem-icera.h
+++ b/plugins/mm-modem-icera.h
@@ -114,9 +114,13 @@ void mm_modem_icera_get_unlock_retries (MMModemIcera *self,
MMModemArrayFn callback,
gpointer user_data);
-void mm_modem_icera_get_band (MMModemIcera *self,
- MMModemUIntFn callback,
- gpointer user_data);
+void mm_modem_icera_get_current_bands (MMModemIcera *self,
+ MMModemUIntFn callback,
+ gpointer user_data);
+
+void mm_modem_icera_get_supported_bands (MMModemIcera *self,
+ MMModemUIntFn callback,
+ gpointer user_data);
void mm_modem_icera_set_band (MMModemIcera *self,
MMModemGsmBand band,
diff --git a/plugins/mm-modem-samsung-gsm.c b/plugins/mm-modem-samsung-gsm.c
index be2c8c7f..50deb80c 100755
--- a/plugins/mm-modem-samsung-gsm.c
+++ b/plugins/mm-modem-samsung-gsm.c
@@ -53,6 +53,7 @@ G_DEFINE_TYPE_EXTENDED (MMModemSamsungGsm, mm_modem_samsung_gsm, MM_TYPE_GENERIC
typedef struct {
gboolean disposed;
MMModemIceraPrivate *icera;
+ MMModemGsmBand supported_bands;
} MMModemSamsungGsmPrivate;
#define IPDPADDR_TAG "%IPDPADDR: "
@@ -112,7 +113,15 @@ get_band (MMModemGsmNetwork *modem,
MMModemUIntFn callback,
gpointer user_data)
{
- mm_modem_icera_get_band (MM_MODEM_ICERA (modem), callback, user_data);
+ mm_modem_icera_get_current_bands (MM_MODEM_ICERA (modem), callback, user_data);
+}
+
+static void
+get_supported_bands (MMGenericGsm *gsm,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ mm_modem_icera_get_supported_bands (MM_MODEM_ICERA (gsm), callback, user_data);
}
static void
@@ -492,4 +501,5 @@ mm_modem_samsung_gsm_class_init (MMModemSamsungGsmClass *klass)
gsm_class->set_allowed_mode = set_allowed_mode;
gsm_class->get_allowed_mode = get_allowed_mode;
gsm_class->get_access_technology = get_access_technology;
+ gsm_class->get_supported_bands = get_supported_bands;
}