diff options
Diffstat (limited to 'src/mm-generic-gsm.c')
-rw-r--r-- | src/mm-generic-gsm.c | 106 |
1 files changed, 86 insertions, 20 deletions
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index c2c84765..bc64fe54 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -2159,46 +2159,96 @@ disconnect_done (MMModem *modem, } static void -disconnect_cgact_done (MMAtSerialPort *port, - GString *response, - GError *error, - gpointer user_data) +disconnect_all_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) { mm_callback_info_schedule ((MMCallbackInfo *) user_data); } static void +disconnect_send_cgact (MMAtSerialPort *port, + gint cid, + MMAtSerialResponseFn callback, + gpointer user_data) +{ + char *command; + + if (cid >= 0) + command = g_strdup_printf ("+CGACT=0,%d", cid); + else { + /* Disable all PDP contexts */ + command = g_strdup_printf ("+CGACT=0"); + } + + mm_at_serial_port_queue_command (port, command, 3, callback, user_data); + g_free (command); +} + +#define DISCONNECT_CGACT_DONE_TAG "disconnect-cgact-done" + +static void disconnect_flash_done (MMSerialPort *port, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; MMGenericGsmPrivate *priv; - char *command; info->error = mm_modem_check_removed (info->modem, error); - /* Ignore NO_CARRIER errors and proceed with the PDP context deactivation */ - if ( info->error - && !g_error_matches (info->error, - MM_MODEM_CONNECT_ERROR, - MM_MODEM_CONNECT_ERROR_NO_CARRIER)) { - mm_callback_info_schedule (info); - return; + if (info->error) { + /* Ignore "NO CARRIER" response when modem disconnects and any flash + * failures we might encounter. Other errors are hard errors. + */ + if ( !g_error_matches (info->error, MM_MODEM_CONNECT_ERROR, MM_MODEM_CONNECT_ERROR_NO_CARRIER) + && !g_error_matches (info->error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_FLASH_FAILED)) { + mm_callback_info_schedule (info); + return; + } + g_clear_error (&info->error); } priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); mm_port_set_connected (priv->data, FALSE); - /* Disconnect the PDP context */ - if (priv->cid >= 0) - command = g_strdup_printf ("+CGACT=0,%d", priv->cid); + /* Don't bother doing the CGACT again if it was done on a secondary port */ + if (mm_callback_info_get_data (info, DISCONNECT_CGACT_DONE_TAG)) + disconnect_all_done (MM_AT_SERIAL_PORT (priv->primary), NULL, NULL, info); else { - /* Disable all PDP contexts */ - command = g_strdup_printf ("+CGACT=0"); + disconnect_send_cgact (MM_AT_SERIAL_PORT (priv->primary), + priv->cid, + disconnect_all_done, + info); } +} - mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), command, 3, disconnect_cgact_done, info); - g_free (command); +static void +disconnect_secondary_cgact_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + MMGenericGsm *self; + MMGenericGsmPrivate *priv; + + if (!info->modem) { + info->error = mm_modem_check_removed (info->modem, error); + mm_callback_info_schedule (info); + return; + } + + self = MM_GENERIC_GSM (info->modem); + priv = MM_GENERIC_GSM_GET_PRIVATE (self); + + /* Now that we've tried deactivating the PDP context on the secondary + * port, continue with flashing the primary port. + */ + if (!error) + mm_callback_info_set_data (info, DISCONNECT_CGACT_DONE_TAG, GUINT_TO_POINTER (TRUE), NULL); + + mm_serial_port_flash (MM_SERIAL_PORT (priv->primary), 1000, TRUE, disconnect_flash_done, info); } static void @@ -2211,7 +2261,23 @@ real_do_disconnect (MMGenericGsm *self, MMCallbackInfo *info; info = mm_callback_info_new (MM_MODEM (self), callback, user_data); - mm_serial_port_flash (MM_SERIAL_PORT (priv->primary), 1000, TRUE, disconnect_flash_done, info); + + /* If the primary port is connected (with PPP) then try sending the PDP + * context deactivation on the secondary port because not all modems will + * respond to flashing (since either the modem or the kernel's serial + * driver doesn't support it). + */ + if ( mm_port_get_connected (MM_PORT (priv->primary)) + && priv->secondary + && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary))) { + disconnect_send_cgact (MM_AT_SERIAL_PORT (priv->secondary), + priv->cid, + disconnect_secondary_cgact_done, + info); + } else { + /* Just flash the primary port */ + mm_serial_port_flash (MM_SERIAL_PORT (priv->primary), 1000, TRUE, disconnect_flash_done, info); + } } static void |