sierra: fix CDMA registration detection in some cases

It turns out that "Modem is [NOT] registered" is not a good indicator
of whether the card has service or not; instead some of the AT!STATUS
response is needed to really determine registration state or not.
This commit is contained in:
Dan Williams
2009-12-18 19:44:48 -08:00
parent 8d42094608
commit db7214c202

View File

@@ -35,6 +35,7 @@ G_DEFINE_TYPE (MMModemSierraCdma, mm_modem_sierra_cdma, MM_TYPE_GENERIC_CDMA)
typedef enum {
SYS_MODE_UNKNOWN,
SYS_MODE_NO_SERVICE,
SYS_MODE_CDMA_1X,
SYS_MODE_EVDO_REV0,
SYS_MODE_EVDO_REVA
@@ -75,6 +76,7 @@ mm_modem_sierra_cdma_new (const char *device,
#define SYS_MODE_EVDO_TAG "HDR"
#define SYS_MODE_1X_TAG "1x"
#define EVDO_REV_TAG "HDR Revision:"
#define SID_TAG "SID:"
static gboolean
get_roam_value (const char *reply, const char *tag, gboolean *roaming)
@@ -99,6 +101,14 @@ get_roam_value (const char *reply, const char *tag, gboolean *roaming)
return FALSE;
}
static gboolean
sys_mode_has_service (SysMode mode)
{
return ( mode == SYS_MODE_CDMA_1X
|| mode == SYS_MODE_EVDO_REV0
|| mode == SYS_MODE_EVDO_REVA);
}
static void
status_done (MMSerialPort *port,
GString *response,
@@ -109,6 +119,7 @@ status_done (MMSerialPort *port,
MMModemSierraCdmaPrivate *priv = MM_MODEM_SIERRA_CDMA_GET_PRIVATE (info->modem);
char **lines, **iter;
gboolean registered = FALSE;
gboolean have_sid = FALSE;
SysMode evdo_mode = SYS_MODE_UNKNOWN;
SysMode sys_mode = SYS_MODE_UNKNOWN;
gboolean cdma_1x_set = FALSE, evdo_set = FALSE;
@@ -129,10 +140,10 @@ status_done (MMSerialPort *port,
* while of course 1x parts only report 1x status. Some modems also do not
* report the Roaming information (MP 555 GPS).
*
* AT!STATUS responses:
*
* Unregistered MC5725:
* -----------------------
* at!status
* Current band: PCS CDMA
* Current channel: 350
* SID: 0 NID: 0 1xRoam: 0 HDRRoam: 0
@@ -140,8 +151,6 @@ status_done (MMSerialPort *port,
* Pilot NOT acquired
* Modem has NOT registered
*
* OK
*
* Registered MC5725:
* -----------------------
* Current band: Cellular Sleep
@@ -151,6 +160,31 @@ status_done (MMSerialPort *port,
* Pilot acquired
* Modem has registered
* HDR Revision: A
*
* Unregistered AC580:
* -----------------------
* Current band: PCS CDMA
* Current channel: 350
* SID: 0 NID: 0 Roaming: 0
* Temp: 39 State: 100 Scan Mode: 0
* Pilot NOT acquired
* Modem has NOT registered
*
* Registered AC580:
* -----------------------
* Current band: Cellular Sleep
* Current channel: 548
* SID: 26 NID: 1 Roaming: 1
* Temp: 39 State: 200 Scan Mode: 0
* Pilot Acquired
* Modem has registered
*/
/* We have to handle the two formats slightly differently; for newer formats
* with "Sys Mode", we consider the modem registered if the Sys Mode is not
* "NO SRV". The explicit registration status is just icing on the cake.
* For older formats (no "Sys Mode") we treat the modem as registered if
* the SID is non-zero.
*/
for (iter = lines; iter && *iter; iter++) {
@@ -194,7 +228,7 @@ status_done (MMSerialPort *port,
while (*p && isspace (*p))
p++;
if (!strncmp (p, SYS_MODE_NO_SERVICE_TAG, strlen (SYS_MODE_NO_SERVICE_TAG)))
sys_mode = SYS_MODE_UNKNOWN;
sys_mode = SYS_MODE_NO_SERVICE;
else if (!strncmp (p, SYS_MODE_EVDO_TAG, strlen (SYS_MODE_EVDO_TAG)))
sys_mode = SYS_MODE_EVDO_REV0;
else if (!strncmp (p, SYS_MODE_1X_TAG, strlen (SYS_MODE_1X_TAG)))
@@ -212,19 +246,27 @@ status_done (MMSerialPort *port,
else if (*p == '0')
evdo_mode = SYS_MODE_EVDO_REV0;
}
/* SID */
p = strstr (*iter, SID_TAG);
if (p) {
p += strlen (SID_TAG);
while (*p && isspace (*p))
p++;
if (isdigit (*p) && (*p != '0'))
have_sid = TRUE;
}
}
if (!registered) {
mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
} else {
/* Update current system mode */
if (sys_mode == SYS_MODE_EVDO_REV0 || sys_mode == SYS_MODE_EVDO_REVA) {
/* Prefer the explicit EVDO mode from EVDO_REV_TAG */
/* Update current system mode */
if (sys_mode == SYS_MODE_EVDO_REV0 || sys_mode == SYS_MODE_EVDO_REVA) {
/* Prefer the explicit EVDO mode from EVDO_REV_TAG */
if (evdo_mode != SYS_MODE_UNKNOWN)
sys_mode = evdo_mode;
}
priv->sys_mode = sys_mode;
}
priv->sys_mode = sys_mode;
if (registered || have_sid || sys_mode_has_service (sys_mode)) {
/* As a backup, if for some reason the registration states didn't get
* figured out by parsing the status info, set some generic registration
* states here.
@@ -235,6 +277,10 @@ status_done (MMSerialPort *port,
/* Ensure EVDO registration mode is set if we're at least in EVDO mode */
if (!evdo_set && (sys_mode == SYS_MODE_EVDO_REV0 || sys_mode == SYS_MODE_EVDO_REVA))
mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED);
} else {
/* Not registered */
mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
}
done: