diff options
author | Dan Williams <dcbw@redhat.com> | 2010-10-25 21:02:43 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2010-10-25 21:02:43 -0500 |
commit | 6f809b589bd8619bf2d0659581389ac3c135d08b (patch) | |
tree | 81d42fa1ba6ce026c39c6584f67b5ab1070c0a3d | |
parent | f93e24dda3fa790ca9dd9a0471aa5fc26495a04c (diff) |
gsm: request ICCID after checking the PIN status
Checking PIN status makes sure the SIM is initialized, and
that has to happen before we try to read the SIM for the
ICCID. So move PIN checking before getting the ICCID, and
retry the ICCID at least once for odd cards like Gobi 1K
that seems to need one more try right after it's done
booting up.
-rw-r--r-- | src/mm-generic-gsm.c | 309 |
1 files changed, 166 insertions, 143 deletions
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index 23d6c551..2ce6add1 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -70,6 +70,8 @@ typedef struct { guint32 pin_check_tries; guint pin_check_timeout; char *simid; + gboolean simid_checked; + guint32 simid_tries; MMModemGsmAllowedMode allowed_mode; @@ -425,137 +427,13 @@ check_valid (MMGenericGsm *self) MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); gboolean new_valid = FALSE; - if (priv->primary && priv->data && priv->pin_checked) + if (priv->primary && priv->data && priv->pin_checked && priv->simid_checked) new_valid = TRUE; mm_modem_base_set_valid (MM_MODEM_BASE (self), new_valid); } -static void initial_pin_check_done (MMModem *modem, GError *error, gpointer user_data); - -static gboolean -pin_check_again (gpointer user_data) -{ - MMGenericGsm *self = MM_GENERIC_GSM (user_data); - MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); - - priv->pin_check_timeout = 0; - check_pin (self, initial_pin_check_done, NULL); - return FALSE; -} - -static void -initial_pin_check_done (MMModem *modem, GError *error, gpointer user_data) -{ - MMGenericGsmPrivate *priv; - - /* modem could have been removed before we get here, in which case - * 'modem' will be NULL. - */ - if (!modem) - return; - - g_return_if_fail (MM_IS_GENERIC_GSM (modem)); - priv = MM_GENERIC_GSM_GET_PRIVATE (modem); - - if ( error - && priv->pin_check_tries++ < 3 - && !mm_modem_base_get_unlock_required (MM_MODEM_BASE (modem))) { - /* Try it again a few times */ - if (priv->pin_check_timeout) - g_source_remove (priv->pin_check_timeout); - priv->pin_check_timeout = g_timeout_add_seconds (2, pin_check_again, modem); - } else { - priv->pin_checked = TRUE; - mm_serial_port_close (MM_SERIAL_PORT (priv->primary)); - check_valid (MM_GENERIC_GSM (modem)); - } -} - -static void -initial_pin_check (MMGenericGsm *self) -{ - GError *error = NULL; - MMGenericGsmPrivate *priv; - - g_return_if_fail (MM_IS_GENERIC_GSM (self)); - priv = MM_GENERIC_GSM_GET_PRIVATE (self); - - g_return_if_fail (priv->primary != NULL); - - if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) - check_pin (self, initial_pin_check_done, NULL); - else { - g_warning ("%s: failed to open serial port: (%d) %s", - __func__, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - - /* Ensure the modem is still somewhat usable if opening the serial - * port fails for some reason. - */ - initial_pin_check_done (MM_MODEM (self), NULL, NULL); - } -} - -static void -initial_imei_check (MMGenericGsm *self) -{ - GError *error = NULL; - MMGenericGsmPrivate *priv; - - g_return_if_fail (MM_IS_GENERIC_GSM (self)); - priv = MM_GENERIC_GSM_GET_PRIVATE (self); - - g_return_if_fail (priv->primary != NULL); - - if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) { - /* Make sure echoing is off */ - mm_at_serial_port_queue_command (priv->primary, "E0", 3, NULL, NULL); - - /* Get modem's imei number */ - mm_modem_gsm_card_get_imei (MM_MODEM_GSM_CARD (self), - get_imei_cb, - NULL); - } else { - g_warning ("%s: failed to open serial port: (%d) %s", - __func__, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - } -} - -static void -initial_info_check (MMGenericGsm *self) -{ - GError *error = NULL; - MMGenericGsmPrivate *priv; - - g_return_if_fail (MM_IS_GENERIC_GSM (self)); - priv = MM_GENERIC_GSM_GET_PRIVATE (self); - - g_return_if_fail (priv->primary != NULL); - - if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) { - /* Make sure echoing is off */ - mm_at_serial_port_queue_command (priv->primary, "E0", 3, NULL, NULL); - mm_modem_base_get_card_info (MM_MODEM_BASE (self), - priv->primary, - NULL, - get_info_cb, - NULL); - } else { - g_warning ("%s: failed to open serial port: (%d) %s", - __func__, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - } -} - static void get_iccid_done (MMModem *modem, const char *response, @@ -564,10 +442,10 @@ get_iccid_done (MMModem *modem, { MMGenericGsmPrivate *priv; const char *p = response; - GChecksum *sum; + GChecksum *sum = NULL; if (error || !response || !strlen (response)) - return; + goto done; sum = g_checksum_new (G_CHECKSUM_SHA1); @@ -575,7 +453,7 @@ get_iccid_done (MMModem *modem, while (*p) { if (!isdigit (*p)) { g_warning ("%s: invalid ICCID format (not a digit)", __func__); - goto out; + goto done; } g_checksum_update (sum, (const guchar *) p++, 1); } @@ -591,10 +469,18 @@ get_iccid_done (MMModem *modem, g_object_notify (G_OBJECT (modem), MM_MODEM_GSM_CARD_SIM_IDENTIFIER); -out: - g_checksum_free (sum); +done: + if (sum) + g_checksum_free (sum); + + if (modem) { + MM_GENERIC_GSM_GET_PRIVATE (modem)->simid_checked = TRUE; + check_valid (MM_GENERIC_GSM (modem)); + } } +#define ICCID_CMD "+CRSM=176,12258,0,0,10" + static void real_get_iccid_done (MMAtSerialPort *port, GString *response, @@ -689,13 +575,27 @@ real_get_iccid_done (MMAtSerialPort *port, mm_callback_info_set_result (info, g_strdup (swapped), g_free); } else { - info->error = g_error_new (MM_MODEM_ERROR, - MM_MODEM_ERROR_GENERAL, - "SIM failed to handle CRSM request (sw1 %d sw2 %d)", - sw1, sw2); + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); + + if (priv->simid_tries++ < 2) { + /* Try one more time... Gobi 1K cards may reply to the first + * request with '+CRSM: 106,134,""' which is bogus because + * subsequent requests work fine. + */ + mm_at_serial_port_queue_command (port, ICCID_CMD, 20, real_get_iccid_done, info); + return; + } else { + info->error = g_error_new (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "SIM failed to handle CRSM request (sw1 %d sw2 %d)", + sw1, sw2); + } } done: + /* Balance open from real_get_sim_iccid() */ + mm_serial_port_close (MM_SERIAL_PORT (port)); + mm_callback_info_schedule (info); } @@ -724,11 +624,7 @@ real_get_sim_iccid (MMGenericGsm *self, info = mm_callback_info_string_new (MM_MODEM (self), callback, callback_data); /* READ BINARY of EFiccid (ICC Identification) ETSI TS 102.221 section 13.2 */ - mm_at_serial_port_queue_command (port, - "+CRSM=176,12258,0,0,10", - 3, - real_get_iccid_done, - info); + mm_at_serial_port_queue_command (port, ICCID_CMD, 20, real_get_iccid_done, info); } static void @@ -738,6 +634,134 @@ initial_iccid_check (MMGenericGsm *self) MM_GENERIC_GSM_GET_CLASS (self)->get_sim_iccid (self, get_iccid_done, NULL); } +static void initial_pin_check_done (MMModem *modem, GError *error, gpointer user_data); + +static gboolean +pin_check_again (gpointer user_data) +{ + MMGenericGsm *self = MM_GENERIC_GSM (user_data); + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + + priv->pin_check_timeout = 0; + check_pin (self, initial_pin_check_done, NULL); + return FALSE; +} + +static void +initial_pin_check_done (MMModem *modem, GError *error, gpointer user_data) +{ + MMGenericGsmPrivate *priv; + + /* modem could have been removed before we get here, in which case + * 'modem' will be NULL. + */ + if (!modem) + return; + + g_return_if_fail (MM_IS_GENERIC_GSM (modem)); + priv = MM_GENERIC_GSM_GET_PRIVATE (modem); + + if ( error + && priv->pin_check_tries++ < 3 + && !mm_modem_base_get_unlock_required (MM_MODEM_BASE (modem))) { + /* Try it again a few times */ + if (priv->pin_check_timeout) + g_source_remove (priv->pin_check_timeout); + priv->pin_check_timeout = g_timeout_add_seconds (2, pin_check_again, modem); + } else { + /* Try to get the SIM ICCID after we've checked PIN status and the SIM + * is ready. + */ + initial_iccid_check (MM_GENERIC_GSM (modem)); + + priv->pin_checked = TRUE; + mm_serial_port_close (MM_SERIAL_PORT (priv->primary)); + } +} + +static void +initial_pin_check (MMGenericGsm *self) +{ + GError *error = NULL; + MMGenericGsmPrivate *priv; + + g_return_if_fail (MM_IS_GENERIC_GSM (self)); + priv = MM_GENERIC_GSM_GET_PRIVATE (self); + + g_return_if_fail (priv->primary != NULL); + + if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) + check_pin (self, initial_pin_check_done, NULL); + else { + g_warning ("%s: failed to open serial port: (%d) %s", + __func__, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + + /* Ensure the modem is still somewhat usable if opening the serial + * port fails for some reason. + */ + initial_pin_check_done (MM_MODEM (self), NULL, NULL); + } +} + +static void +initial_imei_check (MMGenericGsm *self) +{ + GError *error = NULL; + MMGenericGsmPrivate *priv; + + g_return_if_fail (MM_IS_GENERIC_GSM (self)); + priv = MM_GENERIC_GSM_GET_PRIVATE (self); + + g_return_if_fail (priv->primary != NULL); + + if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) { + /* Make sure echoing is off */ + mm_at_serial_port_queue_command (priv->primary, "E0", 3, NULL, NULL); + + /* Get modem's imei number */ + mm_modem_gsm_card_get_imei (MM_MODEM_GSM_CARD (self), + get_imei_cb, + NULL); + } else { + g_warning ("%s: failed to open serial port: (%d) %s", + __func__, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } +} + +static void +initial_info_check (MMGenericGsm *self) +{ + GError *error = NULL; + MMGenericGsmPrivate *priv; + + g_return_if_fail (MM_IS_GENERIC_GSM (self)); + priv = MM_GENERIC_GSM_GET_PRIVATE (self); + + g_return_if_fail (priv->primary != NULL); + + if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) { + /* Make sure echoing is off */ + mm_at_serial_port_queue_command (priv->primary, "E0", 3, NULL, NULL); + mm_modem_base_get_card_info (MM_MODEM_BASE (self), + priv->primary, + NULL, + get_info_cb, + NULL); + } else { + g_warning ("%s: failed to open serial port: (%d) %s", + __func__, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } +} + static gboolean owns_port (MMModem *modem, const char *subsys, const char *name) { @@ -794,10 +818,9 @@ mm_generic_gsm_grab_port (MMGenericGsm *self, /* Get modem's IMEI */ initial_imei_check (self); - /* Try to get the SIM's ICCID */ - initial_iccid_check (self); - - /* Get modem's initial lock/unlock state */ + /* Get modem's initial lock/unlock state; this also ensures the + * SIM is ready by waiting if necessary for the SIM to initalize. + */ initial_pin_check (self); } else if (ptype == MM_PORT_TYPE_SECONDARY) |