aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2010-05-07 13:36:56 -0700
committerDan Williams <dcbw@redhat.com>2010-05-07 13:36:56 -0700
commitd0d847c65a7073ecdced95b69548bf97c7af14f6 (patch)
tree0d7580fbbbabb08e999c6adef64a3eb33d72de06
parent0f6f381e87f81fca3e9808a1fbdfbdbe2fea42e0 (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.c106
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