diff options
author | Dan Williams <dcbw@redhat.com> | 2011-07-19 15:29:44 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2011-07-19 15:36:39 -0500 |
commit | 3e2b6fb24c6f32f6b5898f4c703eed4fc609561d (patch) | |
tree | 9ebeff871a621c5c168897ffda9a8fd448005089 | |
parent | 85000adfe95f948773d4313e3207a1781dc87225 (diff) |
cdma: set Rm interface protocol if required (bgo #641661)
Some providers (CDMA Ukraine) apparently require a specific Rm interface
protocol, so add some Simple Connect dict settings for that and use them
when dialing. Obviously requires the connection manager to also have
support for sending the right bits down to MM.
-rw-r--r-- | introspection/org.freedesktop.ModemManager.Modem.Simple.xml | 5 | ||||
-rw-r--r-- | src/mm-generic-cdma.c | 153 |
2 files changed, 153 insertions, 5 deletions
diff --git a/introspection/org.freedesktop.ModemManager.Modem.Simple.xml b/introspection/org.freedesktop.ModemManager.Modem.Simple.xml index f17b6c90..6c17c0d0 100644 --- a/introspection/org.freedesktop.ModemManager.Modem.Simple.xml +++ b/introspection/org.freedesktop.ModemManager.Modem.Simple.xml @@ -16,11 +16,12 @@ common ones are: 'pin' : string - 'network_id' : string + 'network_id' : string (GSM/HSPA only) 'band' : uint 'network_mode' : uint - 'apn' : string + 'apn' : string (GSM/HSPA only) 'number' : string + 'rm-protocol' : uint (CDMA/EVDO only) (1 - Relay, 2 - Network PPP) </tp:docstring> </arg> </method> diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index 378555b7..4686b85a 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -34,6 +34,15 @@ #define MM_GENERIC_CDMA_PREV_STATE_TAG "prev-state" +typedef enum { + RM_PROTO_ASYNC = 0, + RM_PROTO_RELAY = 1, + RM_PROTO_NETWORK_PPP = 2, + RM_PROTO_NETWORK_SLIP = 3, + RM_PROTO_STU_III = 4 +} RmProtocol; + + static void simple_reg_callback (MMModemCdma *modem, MMModemCdmaRegistrationState cdma_1x_reg_state, MMModemCdmaRegistrationState evdo_reg_state, @@ -67,6 +76,10 @@ typedef struct { gboolean has_spservice; gboolean has_speri; + /* Original and current Rm interface protocol */ + RmProtocol orig_crm; + RmProtocol cur_crm; + guint poll_id; char *meid; @@ -563,6 +576,29 @@ speri_done (MMAtSerialPort *port, } static void +crm_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + const char *p; + unsigned long num; + + if (error) + return; + + p = mm_strip_tag (response->str, "+CRM:"); + if (p) { + errno = 0; + num = strtoul (p, NULL, 10); + if (num >= 0 && num <= 4 && (errno == 0)) { + MM_GENERIC_CDMA_GET_PRIVATE (user_data)->orig_crm = (guint32) num; + MM_GENERIC_CDMA_GET_PRIVATE (user_data)->cur_crm = (guint32) num; + } + } +} + +static void enable_all_done (MMModem *modem, GError *error, gpointer user_data) { MMCallbackInfo *info = user_data; @@ -599,6 +635,9 @@ enable_all_done (MMModem *modem, GError *error, gpointer user_data) /* Check for support of Sprint-specific phone commands */ mm_at_serial_port_queue_command (priv->primary, "+SPSERVICE?", 3, spservice_done, self); mm_at_serial_port_queue_command (priv->primary, "$SPERI?", 3, speri_done, self); + + /* Grab default CRM */ + mm_at_serial_port_queue_command (priv->primary, "+CRM?", 3, crm_done, self); } out: @@ -1960,12 +1999,63 @@ get_registration_state (MMModemCdma *modem, } /*****************************************************************************/ + +static void +set_rm_proto_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (mm_callback_info_check_modem_removed (info) == FALSE) { + if (error) + info->error = g_error_copy (error); + + mm_callback_info_schedule (info); + } +} + +static void +mm_generic_cdma_set_rm_protocol (MMGenericCdma *self, + RmProtocol proto, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + MMAtSerialPort *port; + char *cmd; + + info = mm_callback_info_new (MM_MODEM (self), callback, user_data); + + port = mm_generic_cdma_get_best_at_port (self, &info->error); + if (!port) { + mm_callback_info_schedule (info); + return; + } + g_clear_error (&info->error); + + if (proto < RM_PROTO_ASYNC || proto > RM_PROTO_STU_III) { + g_set_error (&info->error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Invalid Rm interface protocol %d", + proto); + mm_callback_info_schedule (info); + return; + } + + cmd = g_strdup_printf ("+CRM=%d", proto); + mm_at_serial_port_queue_command (port, cmd, 3, set_rm_proto_done, info); + g_free (cmd); +} + +/*****************************************************************************/ /* MMModemSimple interface */ typedef enum { SIMPLE_STATE_BEGIN = 0, SIMPLE_STATE_ENABLE, SIMPLE_STATE_REGISTER, + SIMPLE_STATE_PRE_CONNECT, SIMPLE_STATE_CONNECT, SIMPLE_STATE_DONE } SimpleState; @@ -1991,6 +2081,32 @@ simple_get_string_property (MMCallbackInfo *info, const char *name, GError **err } static gboolean +simple_get_uint_property (MMCallbackInfo *info, + const char *name, + guint32 *out_val, + GError **error) +{ + GHashTable *properties = (GHashTable *) mm_callback_info_get_data (info, "simple-connect-properties"); + GValue *value; + + g_return_val_if_fail (out_val != NULL, FALSE); + + value = (GValue *) g_hash_table_lookup (properties, name); + if (value) { + if (G_VALUE_HOLDS_UINT (value)) { + *out_val = g_value_get_uint (value); + return TRUE; + } + + g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Invalid property type for '%s': %s (uint expected)", + name, G_VALUE_TYPE_NAME (value)); + } + + return FALSE; +} + +static gboolean simple_reg_retry (gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; @@ -2083,10 +2199,11 @@ static void simple_state_machine (MMModem *modem, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem); + MMGenericCdma *self; + MMGenericCdmaPrivate *priv; SimpleState state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "simple-connect-state")); const char *str; - guint id; + guint id, rm_protocol = 0; /* Do nothing if modem removed */ if (!modem || mm_callback_info_check_modem_removed (info)) @@ -2097,12 +2214,17 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data) goto out; } + self = MM_GENERIC_CDMA (info->modem); + priv = MM_GENERIC_CDMA_GET_PRIVATE (self); + switch (state) { case SIMPLE_STATE_BEGIN: + /* Enable state */ state = set_simple_state (info, SIMPLE_STATE_ENABLE); mm_modem_enable (modem, simple_state_machine, info); break; case SIMPLE_STATE_ENABLE: + /* Register state */ state = set_simple_state (info, SIMPLE_STATE_REGISTER); mm_modem_cdma_get_registration_state (MM_MODEM_CDMA (modem), simple_reg_callback, @@ -2114,14 +2236,34 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data) priv->reg_state_changed_id = id; break; case SIMPLE_STATE_REGISTER: + /* Pre Connect state */ registration_cleanup (MM_GENERIC_CDMA (modem), 0, 0); - state = set_simple_state (info, SIMPLE_STATE_CONNECT); + state = set_simple_state (info, SIMPLE_STATE_PRE_CONNECT); mm_modem_set_state (modem, MM_MODEM_STATE_REGISTERED, MM_MODEM_STATE_REASON_NONE); + /* Change the Rm interface protocol due to manager request if needed */ + if (simple_get_uint_property (info, "rm-protocol", &rm_protocol, &info->error)) { + mm_generic_cdma_set_rm_protocol (self, rm_protocol, simple_state_machine, info); + break; + } + + /* Or if the Rm protocol isn't the default, and there was no request + * to change it, do that now. + */ + if (priv->cur_crm != priv->orig_crm) { + mm_generic_cdma_set_rm_protocol (self, priv->orig_crm, simple_state_machine, info); + break; + } + + /* Fall through */ + case SIMPLE_STATE_PRE_CONNECT: + /* Connect state */ + state = set_simple_state (info, SIMPLE_STATE_CONNECT); str = simple_get_string_property (info, "number", &info->error); mm_modem_connect (modem, str, simple_state_machine, info); break; case SIMPLE_STATE_CONNECT: + /* All done! */ state = set_simple_state (info, SIMPLE_STATE_DONE); break; case SIMPLE_STATE_DONE: @@ -2306,10 +2448,15 @@ modem_simple_init (MMModemSimple *class) static void mm_generic_cdma_init (MMGenericCdma *self) { + MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self); + g_signal_connect (self, "notify::" MM_MODEM_VALID, G_CALLBACK (modem_valid_changed), NULL); g_signal_connect (self, "notify::" MM_MODEM_STATE, G_CALLBACK (modem_state_changed), NULL); + + /* Default to Network Layer Rm interface/PPP */ + priv->orig_crm = priv->cur_crm = RM_PROTO_NETWORK_PPP; } static void |