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.
This commit is contained in:
Dan Williams
2010-03-10 14:39:10 -08:00
parent b7858ba235
commit 59b75b5194
2 changed files with 94 additions and 36 deletions

View File

@@ -81,7 +81,7 @@ typedef struct {
guint signal_quality_id; guint signal_quality_id;
time_t signal_quality_timestamp; time_t signal_quality_timestamp;
guint32 signal_quality; guint32 signal_quality;
guint32 cid; gint cid;
MMSerialPort *primary; MMSerialPort *primary;
MMSerialPort *secondary; MMSerialPort *secondary;
@@ -141,15 +141,7 @@ mm_generic_gsm_new (const char *device,
NULL)); NULL));
} }
void gint
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
mm_generic_gsm_get_cid (MMGenericGsm *modem) mm_generic_gsm_get_cid (MMGenericGsm *modem)
{ {
g_return_val_if_fail (MM_IS_GENERIC_GSM (modem), 0); g_return_val_if_fail (MM_IS_GENERIC_GSM (modem), 0);
@@ -821,7 +813,7 @@ enable (MMModem *modem,
} }
/* First, reset the previously used CID */ /* 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)) { if (!mm_serial_port_open (priv->primary, &error)) {
MMCallbackInfo *info; MMCallbackInfo *info;
@@ -907,7 +899,9 @@ disable (MMModem *modem,
MMModemState state; MMModemState state;
/* First, reset the previously used CID and clean up registration */ /* 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)); mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (modem));
if (priv->poll_id) { if (priv->poll_id) {
@@ -1919,16 +1913,16 @@ connect (MMModem *modem,
} }
static void static void
disconnect_flash_done (MMSerialPort *port, disconnect_done (MMModem *modem,
GError *error, GError *error,
gpointer user_data) gpointer user_data)
{ {
MMCallbackInfo *info = (MMCallbackInfo *) user_data; MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMModemState prev_state; 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->error) {
if (info->modem) { if (info->modem && modem) {
/* Reset old state since the operation failed */ /* Reset old state since the operation failed */
prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_GSM_PREV_STATE_TAG)); 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), mm_modem_set_state (MM_MODEM (info->modem),
@@ -1936,28 +1930,77 @@ disconnect_flash_done (MMSerialPort *port,
MM_MODEM_STATE_REASON_NONE); MM_MODEM_STATE_REASON_NONE);
} }
} else { } else {
MMGenericGsm *self = MM_GENERIC_GSM (info->modem); MMGenericGsm *self = MM_GENERIC_GSM (modem);
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
mm_port_set_connected (priv->data, FALSE); mm_port_set_connected (priv->data, FALSE);
priv->cid = -1;
mm_generic_gsm_update_enabled_state (self, FALSE, MM_MODEM_STATE_REASON_NONE); mm_generic_gsm_update_enabled_state (self, FALSE, MM_MODEM_STATE_REASON_NONE);
} }
mm_callback_info_schedule (info); mm_callback_info_schedule (info);
} }
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 static void
disconnect (MMModem *modem, disconnect (MMModem *modem,
MMModemFn callback, MMModemFn callback,
gpointer user_data) 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; MMCallbackInfo *info;
MMModemState state; 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); info = mm_callback_info_new (modem, callback, user_data);
/* Cache the previous state so we can reset it if the operation fails */ /* Cache the previous state so we can reset it if the operation fails */
@@ -1968,7 +2011,9 @@ disconnect (MMModem *modem,
NULL); NULL);
mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE); 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 static void
@@ -2020,6 +2065,8 @@ scan (MMModemGsmNetwork *modem,
/* SetApn */ /* SetApn */
#define APN_CID_TAG "generic-gsm-cid"
static void static void
set_apn_done (MMSerialPort *port, set_apn_done (MMSerialPort *port,
GString *response, GString *response,
@@ -2028,11 +2075,12 @@ set_apn_done (MMSerialPort *port,
{ {
MMCallbackInfo *info = (MMCallbackInfo *) user_data; MMCallbackInfo *info = (MMCallbackInfo *) user_data;
if (error) info->error = mm_modem_check_removed (info->modem, error);
info->error = g_error_copy (error); if (!info->error) {
else MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
mm_generic_gsm_set_cid (MM_GENERIC_GSM (info->modem),
GPOINTER_TO_UINT (mm_callback_info_get_data (info, "cid"))); priv->cid = GPOINTER_TO_INT (mm_callback_info_get_data (info, APN_CID_TAG));
}
mm_callback_info_schedule (info); 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"); const char *apn = (const char *) mm_callback_info_get_data (info, "apn");
char *command; 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); command = g_strdup_printf ("+CGDCONT=%d,\"IP\",\"%s\"", cid, apn);
mm_serial_port_queue_command (port, command, 3, set_apn_done, info); 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; MMCallbackInfo *info = (MMCallbackInfo *) user_data;
gboolean found = FALSE; gboolean found = FALSE;
if (error) info->error = mm_modem_check_removed (info->modem, error);
info->error = g_error_copy (error); if (info->error)
goto done;
else if (g_str_has_prefix (response->str, "+CGDCONT: ")) { else if (g_str_has_prefix (response->str, "+CGDCONT: ")) {
GRegex *r; GRegex *r;
GMatchInfo *match_info; GMatchInfo *match_info;
@@ -2137,7 +2186,7 @@ existing_apns_read (MMSerialPort *port,
apn = g_match_info_fetch (match_info, 3); apn = g_match_info_fetch (match_info, 3);
if (!strcmp (apn, new_apn)) { 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; found = TRUE;
} }
@@ -2165,11 +2214,13 @@ existing_apns_read (MMSerialPort *port,
MM_MODEM_ERROR_GENERAL, MM_MODEM_ERROR_GENERAL,
"Could not parse the response"); "Could not parse the response");
done:
if (found || info->error) if (found || info->error)
mm_callback_info_schedule (info); mm_callback_info_schedule (info);
else else {
/* APN not configured on the card. Get the allowed CID range */ /* APN not configured on the card. Get the allowed CID range */
mm_serial_port_queue_command_cached (port, "+CGDCONT=?", 3, cid_range_read, info); mm_serial_port_queue_command_cached (port, "+CGDCONT=?", 3, cid_range_read, info);
}
} }
static void static void
@@ -2983,6 +3034,7 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass)
klass->do_enable = real_do_enable; klass->do_enable = real_do_enable;
klass->do_enable_power_up_done = real_do_enable_power_up_done; klass->do_enable_power_up_done = real_do_enable_power_up_done;
klass->do_disconnect = real_do_disconnect;
/* Properties */ /* Properties */
g_object_class_override_property (object_class, g_object_class_override_property (object_class,

View File

@@ -79,6 +79,14 @@ typedef struct {
GError *error, GError *error,
MMCallbackInfo *info); MMCallbackInfo *info);
/* Called to terminate the active data call and deactivate the given PDP
* context.
*/
void (*do_disconnect) (MMGenericGsm *self,
gint cid,
MMModemFn callback,
gpointer user_data);
/* Called by the generic class to set the allowed operating mode of the device */ /* Called by the generic class to set the allowed operating mode of the device */
void (*set_allowed_mode) (MMGenericGsm *self, void (*set_allowed_mode) (MMGenericGsm *self,
MMModemGsmAllowedMode mode, MMModemGsmAllowedMode mode,
@@ -110,10 +118,8 @@ MMModem *mm_generic_gsm_new (const char *device,
void mm_generic_gsm_pending_registration_stop (MMGenericGsm *modem); void mm_generic_gsm_pending_registration_stop (MMGenericGsm *modem);
void mm_generic_gsm_set_cid (MMGenericGsm *modem, gint mm_generic_gsm_get_cid (MMGenericGsm *modem);
guint32 cid);
guint32 mm_generic_gsm_get_cid (MMGenericGsm *modem);
void mm_generic_gsm_set_reg_status (MMGenericGsm *modem, void mm_generic_gsm_set_reg_status (MMGenericGsm *modem,
MMModemGsmNetworkRegStatus status); MMModemGsmNetworkRegStatus status);