aboutsummaryrefslogtreecommitdiff
path: root/src/mm-generic-gsm.c
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2010-03-10 14:39:10 -0800
committerDan Williams <dcbw@redhat.com>2010-03-10 14:39:10 -0800
commit59b75b5194c6f2a649ca2a4bd6747f74b220d773 (patch)
treeaeebb7025763c19b7b0083471cdf11e11e3badf3 /src/mm-generic-gsm.c
parentb7858ba235c046a514fbc79e18ac9faa75982032 (diff)
gsm: clean up disconnect handling
Allow subclasses to override disconnect more cleanly so that modem state gets handled correctly when the disconnect is complete. Also fix up PDP Context ID handle (cid) so that subclasses can get the previously-activated context ID when disconnecting, and let the cid be an int since '0' is a valid context number. For the generic devices, this also attempts to actually deactivate the PDP context to ensure that the data session is terminated.
Diffstat (limited to 'src/mm-generic-gsm.c')
-rw-r--r--src/mm-generic-gsm.c118
1 files changed, 85 insertions, 33 deletions
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index 5a50b24a..dcb37c32 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -81,7 +81,7 @@ typedef struct {
guint signal_quality_id;
time_t signal_quality_timestamp;
guint32 signal_quality;
- guint32 cid;
+ gint cid;
MMSerialPort *primary;
MMSerialPort *secondary;
@@ -141,15 +141,7 @@ mm_generic_gsm_new (const char *device,
NULL));
}
-void
-mm_generic_gsm_set_cid (MMGenericGsm *modem, guint32 cid)
-{
- g_return_if_fail (MM_IS_GENERIC_GSM (modem));
-
- MM_GENERIC_GSM_GET_PRIVATE (modem)->cid = cid;
-}
-
-guint32
+gint
mm_generic_gsm_get_cid (MMGenericGsm *modem)
{
g_return_val_if_fail (MM_IS_GENERIC_GSM (modem), 0);
@@ -821,7 +813,7 @@ enable (MMModem *modem,
}
/* First, reset the previously used CID */
- mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0);
+ priv->cid = -1;
if (!mm_serial_port_open (priv->primary, &error)) {
MMCallbackInfo *info;
@@ -907,7 +899,9 @@ disable (MMModem *modem,
MMModemState state;
/* First, reset the previously used CID and clean up registration */
- mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0);
+ g_warn_if_fail (priv->cid == -1);
+ priv->cid = -1;
+
mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (modem));
if (priv->poll_id) {
@@ -1919,16 +1913,16 @@ connect (MMModem *modem,
}
static void
-disconnect_flash_done (MMSerialPort *port,
- GError *error,
- gpointer user_data)
+disconnect_done (MMModem *modem,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMModemState prev_state;
- info->error = mm_modem_check_removed (info->modem, error);
+ info->error = mm_modem_check_removed (modem, error);
if (info->error) {
- if (info->modem) {
+ if (info->modem && modem) {
/* Reset old state since the operation failed */
prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_GSM_PREV_STATE_TAG));
mm_modem_set_state (MM_MODEM (info->modem),
@@ -1936,10 +1930,11 @@ disconnect_flash_done (MMSerialPort *port,
MM_MODEM_STATE_REASON_NONE);
}
} else {
- MMGenericGsm *self = MM_GENERIC_GSM (info->modem);
+ MMGenericGsm *self = MM_GENERIC_GSM (modem);
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
mm_port_set_connected (priv->data, FALSE);
+ priv->cid = -1;
mm_generic_gsm_update_enabled_state (self, FALSE, MM_MODEM_STATE_REASON_NONE);
}
@@ -1947,17 +1942,65 @@ disconnect_flash_done (MMSerialPort *port,
}
static void
+disconnect_cgact_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ mm_callback_info_schedule ((MMCallbackInfo *) user_data);
+}
+
+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);
+ if (info->error) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ /* Disconnect the PDP context */
+ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
+ if (priv->cid >= 0)
+ command = g_strdup_printf ("+CGACT=0,%d", priv->cid);
+ else {
+ /* Disable all PDP contexts */
+ command = g_strdup_printf ("+CGACT=0");
+ }
+
+ mm_serial_port_queue_command (port, command, 60, disconnect_cgact_done, info);
+ g_free (command);
+}
+
+static void
+real_do_disconnect (MMGenericGsm *self,
+ gint cid,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new (MM_MODEM (self), callback, user_data);
+ mm_serial_port_flash (priv->primary, 1000, disconnect_flash_done, info);
+}
+
+static void
disconnect (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
- MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
+ MMGenericGsm *self = MM_GENERIC_GSM (modem);
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
MMCallbackInfo *info;
MMModemState state;
- /* First, reset the previously used CID */
- mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0);
-
info = mm_callback_info_new (modem, callback, user_data);
/* Cache the previous state so we can reset it if the operation fails */
@@ -1968,7 +2011,9 @@ disconnect (MMModem *modem,
NULL);
mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE);
- mm_serial_port_flash (priv->primary, 1000, disconnect_flash_done, info);
+
+ g_assert (MM_GENERIC_GSM_GET_CLASS (self)->do_disconnect);
+ MM_GENERIC_GSM_GET_CLASS (self)->do_disconnect (self, priv->cid, disconnect_done, info);
}
static void
@@ -2020,6 +2065,8 @@ scan (MMModemGsmNetwork *modem,
/* SetApn */
+#define APN_CID_TAG "generic-gsm-cid"
+
static void
set_apn_done (MMSerialPort *port,
GString *response,
@@ -2028,11 +2075,12 @@ set_apn_done (MMSerialPort *port,
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- if (error)
- info->error = g_error_copy (error);
- else
- mm_generic_gsm_set_cid (MM_GENERIC_GSM (info->modem),
- GPOINTER_TO_UINT (mm_callback_info_get_data (info, "cid")));
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (!info->error) {
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
+
+ priv->cid = GPOINTER_TO_INT (mm_callback_info_get_data (info, APN_CID_TAG));
+ }
mm_callback_info_schedule (info);
}
@@ -2095,7 +2143,7 @@ cid_range_read (MMSerialPort *port,
const char *apn = (const char *) mm_callback_info_get_data (info, "apn");
char *command;
- mm_callback_info_set_data (info, "cid", GUINT_TO_POINTER (cid), NULL);
+ mm_callback_info_set_data (info, APN_CID_TAG, GINT_TO_POINTER (cid), NULL);
command = g_strdup_printf ("+CGDCONT=%d,\"IP\",\"%s\"", cid, apn);
mm_serial_port_queue_command (port, command, 3, set_apn_done, info);
@@ -2112,8 +2160,9 @@ existing_apns_read (MMSerialPort *port,
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
gboolean found = FALSE;
- if (error)
- info->error = g_error_copy (error);
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (info->error)
+ goto done;
else if (g_str_has_prefix (response->str, "+CGDCONT: ")) {
GRegex *r;
GMatchInfo *match_info;
@@ -2137,7 +2186,7 @@ existing_apns_read (MMSerialPort *port,
apn = g_match_info_fetch (match_info, 3);
if (!strcmp (apn, new_apn)) {
- mm_generic_gsm_set_cid (MM_GENERIC_GSM (info->modem), (guint32) num_cid);
+ MM_GENERIC_GSM_GET_PRIVATE (info->modem)->cid = num_cid;
found = TRUE;
}
@@ -2165,11 +2214,13 @@ existing_apns_read (MMSerialPort *port,
MM_MODEM_ERROR_GENERAL,
"Could not parse the response");
+done:
if (found || info->error)
mm_callback_info_schedule (info);
- else
+ else {
/* APN not configured on the card. Get the allowed CID range */
mm_serial_port_queue_command_cached (port, "+CGDCONT=?", 3, cid_range_read, info);
+ }
}
static void
@@ -2983,6 +3034,7 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass)
klass->do_enable = real_do_enable;
klass->do_enable_power_up_done = real_do_enable_power_up_done;
+ klass->do_disconnect = real_do_disconnect;
/* Properties */
g_object_class_override_property (object_class,