diff options
author | Dan Williams <dcbw@redhat.com> | 2010-05-07 13:36:56 -0700 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2010-05-07 13:36:56 -0700 |
commit | d0d847c65a7073ecdced95b69548bf97c7af14f6 (patch) | |
tree | 0d7580fbbbabb08e999c6adef64a3eb33d72de06 | |
parent | 0f6f381e87f81fca3e9808a1fbdfbdbe2fea42e0 (diff) |
gsm: try PDP context deactivation on the second port first
There are some cases where flashing the primary port doesn't work
either due to stupid modem firmware or crappy kernel drivers. So
if we have a secondary port, try sending the PDP deactivation
command to the secondary port first, and if that fails send it
to the primary port after the primary port gets flashed. This
increases the chances that the +CGACT request will be successful.
Some modems (Huawei, ZTE) don't like +CGACT on the secondary port,
but when that fails, the code falls back to previous behavior of
flashing and sending CGACT to the primary port.
-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 |