diff options
-rw-r--r-- | src/mm-generic-cdma.c | 130 | ||||
-rw-r--r-- | src/mm-modem-helpers.c | 233 | ||||
-rw-r--r-- | src/mm-modem-helpers.h | 4 |
3 files changed, 342 insertions, 25 deletions
diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index 728d8766..b708882b 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -391,8 +391,14 @@ spservice_done (MMAtSerialPort *port, GError *error, gpointer user_data) { - if (!error) + if (!error) { MM_GENERIC_CDMA_GET_PRIVATE (user_data)->has_spservice = TRUE; + + /* +SPSERVICE provides a better indicator of registration status than + * +CSS, which some devices implement inconsistently. + */ + MM_GENERIC_CDMA_GET_PRIVATE (user_data)->reg_try_css = FALSE; + } } static void @@ -1165,22 +1171,26 @@ static void set_callback_1x_state_helper (MMCallbackInfo *info, MMModemCdmaRegistrationState new_state) { - MMGenericCdma *self = MM_GENERIC_CDMA (info->modem); - MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem); + if (info->modem) { + MMGenericCdma *self = MM_GENERIC_CDMA (info->modem); + MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem); - mm_generic_cdma_set_1x_registration_state (self, new_state); - mm_generic_cdma_query_reg_state_set_callback_1x_state (info, priv->cdma_1x_reg_state); + mm_generic_cdma_set_1x_registration_state (self, new_state); + mm_generic_cdma_query_reg_state_set_callback_1x_state (info, priv->cdma_1x_reg_state); + } } static void set_callback_evdo_state_helper (MMCallbackInfo *info, MMModemCdmaRegistrationState new_state) { - MMGenericCdma *self = MM_GENERIC_CDMA (info->modem); - MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem); + if (info->modem) { + MMGenericCdma *self = MM_GENERIC_CDMA (info->modem); + MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem); - mm_generic_cdma_set_evdo_registration_state (self, new_state); - mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, priv->evdo_reg_state); + mm_generic_cdma_set_evdo_registration_state (self, new_state); + mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, priv->evdo_reg_state); + } } static void @@ -1203,22 +1213,87 @@ reg_state_query_done (MMModemCdma *cdma, } static void -query_subclass_registration_state (MMGenericCdma *self, MMCallbackInfo *info) +reg_query_speri_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + MMModemCdmaRegistrationState cdma_state; + MMModemCdmaRegistrationState evdo_state; + + cdma_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "tmp-cdma-state")); + evdo_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "tmp-evdo-state")); + + if (!error) { + gboolean roam = FALSE; + + if (mm_cdma_parse_speri_response (response->str, &roam, NULL)) { + cdma_state = roam ? MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING + : MM_MODEM_CDMA_REGISTRATION_STATE_HOME; + evdo_state = roam ? MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING + : MM_MODEM_CDMA_REGISTRATION_STATE_HOME; + } + } + + set_callback_1x_state_helper (info, cdma_state); + set_callback_evdo_state_helper (info, evdo_state); + mm_callback_info_schedule (info); +} + +static void +reg_query_spservice_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + MMModemCdmaRegistrationState cdma_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; + MMModemCdmaRegistrationState evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; + + if (error) + info->error = g_error_copy (error); + else if (mm_cdma_parse_spservice_response (response->str, + &cdma_state, + &evdo_state)) { + if (MM_GENERIC_CDMA_GET_PRIVATE (info->modem)->has_speri) { + /* Get roaming status to override generic registration state */ + mm_callback_info_set_data (info, "tmp-cdma-state", GUINT_TO_POINTER (cdma_state), NULL); + mm_callback_info_set_data (info, "tmp-evdo-state", GUINT_TO_POINTER (evdo_state), NULL); + mm_at_serial_port_queue_command (port, "$SPERI?", 3, reg_query_speri_done, info); + return; + } + } + + set_callback_1x_state_helper (info, cdma_state); + set_callback_evdo_state_helper (info, evdo_state); + mm_callback_info_schedule (info); +} + +static void +real_query_registration_state (MMGenericCdma *self, + MMModemCdmaRegistrationStateFn callback, + gpointer user_data) { - /* Let subclasses figure out roaming and detailed registration state */ - if (MM_GENERIC_CDMA_GET_CLASS (self)->query_registration_state) { - MM_GENERIC_CDMA_GET_CLASS (self)->query_registration_state (self, - reg_state_query_done, - info); + MMCallbackInfo *info; + MMAtSerialPort *port; + + info = mm_generic_cdma_query_reg_state_callback_info_new (self, callback, user_data); + + port = mm_generic_cdma_get_best_at_port (self, &info->error); + if (!port) { + mm_callback_info_schedule (info); + return; + } + + if (MM_GENERIC_CDMA_GET_PRIVATE (self)->has_spservice) { + /* Try Sprint-specific commands */ + mm_at_serial_port_queue_command (port, "+SPSERVICE?", 3, reg_query_spservice_done, info); } else { - /* Or if the subclass doesn't implement more specific checking, - * assume we're registered. - */ - reg_state_query_done (MM_MODEM_CDMA (self), - MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED, - MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED, - NULL, - info); + /* Assume we're registered if we passed CAD and CSS checking */ + set_callback_1x_state_helper (info, MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED); + set_callback_evdo_state_helper (info, MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED); + mm_callback_info_schedule (info); } } @@ -1248,7 +1323,9 @@ reg_state_css_response (MMModemCdma *cdma, return; } - query_subclass_registration_state (MM_GENERIC_CDMA (info->modem), info); + MM_GENERIC_CDMA_GET_CLASS (cdma)->query_registration_state (MM_GENERIC_CDMA (info->modem), + reg_state_query_done, + info); } static void @@ -1299,7 +1376,9 @@ get_analog_digital_done (MMAtSerialPort *port, /* Subclass knows that AT+CSS? will respond incorrectly to EVDO * state, so skip AT+CSS? query. */ - query_subclass_registration_state (MM_GENERIC_CDMA (info->modem), info); + MM_GENERIC_CDMA_GET_CLASS (info->modem)->query_registration_state (MM_GENERIC_CDMA (info->modem), + reg_state_query_done, + info); } return; } else { @@ -1765,6 +1844,7 @@ mm_generic_cdma_class_init (MMGenericCdmaClass *klass) object_class->dispose = dispose; object_class->finalize = finalize; object_class->constructor = constructor; + klass->query_registration_state = real_query_registration_state; /* Properties */ g_object_class_override_property (object_class, diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index 0a2bb623..1f7a7888 100644 --- a/src/mm-modem-helpers.c +++ b/src/mm-modem-helpers.c @@ -18,6 +18,7 @@ #include <string.h> #include <ctype.h> #include <stdlib.h> +#include <errno.h> #include "mm-errors.h" #include "mm-modem-helpers.h" @@ -469,6 +470,238 @@ mm_cdma_parse_spservice_response (const char *reply, /*************************************************************************/ +typedef struct { + int num; + gboolean roam_ind; + const char *banner; +} EriItem; + +/* NOTE: these may be Sprint-specific for now... */ +static const EriItem eris[] = { + { 0, TRUE, "Digital or Analog Roaming" }, + { 1, FALSE, "Home" }, + { 2, TRUE, "Digital or Analog Roaming" }, + { 3, TRUE, "Out of neighborhood" }, + { 4, TRUE, "Out of building" }, + { 5, TRUE, "Preferred system" }, + { 6, TRUE, "Available System" }, + { 7, TRUE, "Alliance Partner" }, + { 8, TRUE, "Premium Partner" }, + { 9, TRUE, "Full Service Functionality" }, + { 10, TRUE, "Partial Service Functionality" }, + { 64, TRUE, "Preferred system" }, + { 65, TRUE, "Available System" }, + { 66, TRUE, "Alliance Partner" }, + { 67, TRUE, "Premium Partner" }, + { 68, TRUE, "Full Service Functionality" }, + { 69, TRUE, "Partial Service Functionality" }, + { 70, TRUE, "Analog A" }, + { 71, TRUE, "Analog B" }, + { 72, TRUE, "CDMA 800 A" }, + { 73, TRUE, "CDMA 800 B" }, + { 74, TRUE, "International Roaming" }, + { 75, TRUE, "Extended Network" }, + { 76, FALSE, "Campus" }, + { 77, FALSE, "In Building" }, + { 78, TRUE, "Regional" }, + { 79, TRUE, "Community" }, + { 80, TRUE, "Business" }, + { 81, TRUE, "Zone 1" }, + { 82, TRUE, "Zone 2" }, + { 83, TRUE, "National" }, + { 84, TRUE, "Local" }, + { 85, TRUE, "City" }, + { 86, TRUE, "Government" }, + { 87, TRUE, "USA" }, + { 88, TRUE, "State" }, + { 89, TRUE, "Resort" }, + { 90, TRUE, "Headquarters" }, + { 91, TRUE, "Personal" }, + { 92, FALSE, "Home" }, + { 93, TRUE, "Residential" }, + { 94, TRUE, "University" }, + { 95, TRUE, "College" }, + { 96, TRUE, "Hotel Guest" }, + { 97, TRUE, "Rental" }, + { 98, FALSE, "Corporate" }, + { 99, FALSE, "Home Provider" }, + { 100, FALSE, "Campus" }, + { 101, FALSE, "In Building" }, + { 102, TRUE, "Regional" }, + { 103, TRUE, "Community" }, + { 104, TRUE, "Business" }, + { 105, TRUE, "Zone 1" }, + { 106, TRUE, "Zone 2" }, + { 107, TRUE, "National" }, + { 108, TRUE, "Local" }, + { 109, TRUE, "City" }, + { 110, TRUE, "Government" }, + { 111, TRUE, "USA" }, + { 112, TRUE, "State" }, + { 113, TRUE, "Resort" }, + { 114, TRUE, "Headquarters" }, + { 115, TRUE, "Personal" }, + { 116, FALSE, "Home" }, + { 117, TRUE, "Residential" }, + { 118, TRUE, "University" }, + { 119, TRUE, "College" }, + { 120, TRUE, "Hotel Guest" }, + { 121, TRUE, "Rental" }, + { 122, FALSE, "Corporate" }, + { 123, FALSE, "Home Provider" }, + { 124, TRUE, "International" }, + { 125, TRUE, "International" }, + { 126, TRUE, "International" }, + { 127, FALSE, "Premium Service" }, + { 128, FALSE, "Enhanced Service" }, + { 129, FALSE, "Enhanced Digital" }, + { 130, FALSE, "Enhanced Roaming" }, + { 131, FALSE, "Alliance Service" }, + { 132, FALSE, "Alliance Network" }, + { 133, FALSE, "Data Roaming" }, /* Sprint: Vision Roaming */ + { 134, FALSE, "Extended Service" }, + { 135, FALSE, "Expanded Services" }, + { 136, FALSE, "Expanded Network" }, + { 137, TRUE, "Premium Service" }, + { 138, TRUE, "Enhanced Service" }, + { 139, TRUE, "Enhanced Digital" }, + { 140, TRUE, "Enhanced Roaming" }, + { 141, TRUE, "Alliance Service" }, + { 142, TRUE, "Alliance Network" }, + { 143, TRUE, "Data Roaming" }, /* Sprint: Vision Roaming */ + { 144, TRUE, "Extended Service" }, + { 145, TRUE, "Expanded Services" }, + { 146, TRUE, "Expanded Network" }, + { 147, TRUE, "Premium Service" }, + { 148, TRUE, "Enhanced Service" }, + { 149, TRUE, "Enhanced Digital" }, + { 150, TRUE, "Enhanced Roaming" }, + { 151, TRUE, "Alliance Service" }, + { 152, TRUE, "Alliance Network" }, + { 153, TRUE, "Data Roaming" }, /* Sprint: Vision Roaming */ + { 154, TRUE, "Extended Service" }, + { 155, TRUE, "Expanded Services" }, + { 156, TRUE, "Expanded Network" }, + { 157, TRUE, "Premium International" }, + { 158, TRUE, "Premium International" }, + { 159, TRUE, "Premium International" }, + { 160, TRUE, NULL }, + { 161, TRUE, NULL }, + { 162, FALSE, NULL }, + { 163, FALSE, NULL }, + { 164, FALSE, "Extended Voice/Data Network" }, + { 165, FALSE, "Extended Voice/Data Network" }, + { 166, TRUE, "Extended Voice/Data Network" }, + { 167, FALSE, "Extended Broadband" }, + { 168, FALSE, "Extended Broadband" }, + { 169, TRUE, "Extended Broadband" }, + { 170, FALSE, "Extended Data" }, + { 171, FALSE, "Extended Data" }, + { 172, TRUE, "Extended Data" }, + { 173, FALSE, "Extended Data Network" }, + { 174, FALSE, "Extended Data Network" }, + { 175, TRUE, "Extended Data Network" }, + { 176, FALSE, "Extended Network" }, + { 177, FALSE, "Extended Network" }, + { 178, TRUE, "Extended Network" }, + { 179, FALSE, "Extended Service" }, + { 180, TRUE, "Extended Service" }, + { 181, FALSE, "Extended Voice" }, + { 182, FALSE, "Extended Voice" }, + { 183, TRUE, "Extended Voice" }, + { 184, FALSE, "Extended Voice/Data" }, + { 185, FALSE, "Extended Voice/Data" }, + { 186, TRUE, "Extended Voice/Data" }, + { 187, FALSE, "Extended Voice Network" }, + { 188, FALSE, "Extended Voice Network" }, + { 189, TRUE, "Extended Voice Network" }, + { 190, FALSE, "Extended Voice/Data" }, + { 191, FALSE, "Extended Voice/Data" }, + { 192, TRUE, "Extended Voice/Data" }, + { 193, TRUE, "International" }, + { 194, FALSE, "International Services" }, + { 195, FALSE, "International Voice" }, + { 196, FALSE, "International Voice/Data" }, + { 197, FALSE, "International Voice/Data" }, + { 198, TRUE, "International Voice/Data" }, + { 199, FALSE, "Extended Voice/Data Network" }, + { 200, TRUE, "Extended Voice/Data Network" }, + { 201, TRUE, "Extended Voice/Data Network" }, + { 202, FALSE, "Extended Broadband" }, + { 203, TRUE, "Extended Broadband" }, + { 204, TRUE, "Extended Broadband" }, + { 205, FALSE, "Extended Data" }, + { 206, TRUE, "Extended Data" }, + { 207, TRUE, "Extended Data" }, + { 208, FALSE, "Extended Data Network" }, + { 209, TRUE, "Extended Data Network" }, + { 210, TRUE, "Extended Data Network" }, + { 211, FALSE, "Extended Network" }, + { 212, TRUE, "Extended Network" }, + { 213, FALSE, "Extended Service" }, + { 214, TRUE, "Extended Service" }, + { 215, TRUE, "Extended Service" }, + { 216, FALSE, "Extended Voice" }, + { 217, TRUE, "Extended Voice" }, + { 218, TRUE, "Extended Voice" }, + { 219, FALSE, "Extended Voice/Data" }, + { 220, TRUE, "Extended Voice/Data" }, + { 221, TRUE, "Extended Voice/Data" }, + { 222, FALSE, "Extended Voice Network" }, + { 223, FALSE, "Extended Voice Network" }, + { 224, TRUE, "Extended Voice Network" }, + { 225, FALSE, "Extended Voice/Data" }, + { 226, TRUE, "Extended Voice/Data" }, + { 227, TRUE, "Extended Voice/Data" }, + { 228, TRUE, "International" }, + { 229, TRUE, "International" }, + { 230, TRUE, "International Services" }, + { 231, TRUE, "International Voice" }, + { 232, FALSE, "International Voice/Data" }, + { 233, TRUE, "International Voice/Data" }, + { 234, TRUE, "International Voice/Data" }, + { 235, TRUE, "Premium International" }, + { 236, TRUE, NULL }, + { 237, TRUE, NULL }, + { 238, FALSE, NULL }, + { 239, FALSE, NULL }, + { -1, FALSE, NULL }, +}; + +gboolean +mm_cdma_parse_speri_response (const char *reply, + gboolean *out_roaming, + const char **out_desc) +{ + const char *p; + long int ind; + const EriItem *iter = &eris[0]; + gboolean found = FALSE; + + g_return_val_if_fail (reply != NULL, FALSE); + g_return_val_if_fail (out_roaming != NULL, FALSE); + + p = mm_strip_tag (reply, "$SPERI:"); + errno = 0; + ind = strtol (p, NULL, 10); + if (errno == 0) { + while (iter->num != -1) { + if (iter->num == ind) { + *out_roaming = iter->roam_ind; + if (out_desc) + *out_desc = iter->banner; + found = TRUE; + break; + } + iter++; + } + } + + return found; +} + +/*************************************************************************/ + const char * mm_strip_tag (const char *str, const char *cmd) { diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h index 3e398e59..0ef16074 100644 --- a/src/mm-modem-helpers.h +++ b/src/mm-modem-helpers.h @@ -47,5 +47,9 @@ gboolean mm_cdma_parse_spservice_response (const char *reply, MMModemCdmaRegistrationState *out_cdma_1x_state, MMModemCdmaRegistrationState *out_evdo_state); +gboolean mm_cdma_parse_speri_response (const char *reply, + gboolean *out_roaming, + const char **out_desc); + #endif /* MM_MODEM_HELPERS_H */ |