From 6e9d980e8c29974f9b641a1f6bc3be5212500901 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Tue, 21 Jun 2011 12:54:09 +0200 Subject: [PATCH 1/8] gsm: allow plugins to check if they need to issue the power-up command Some modems only like the power-up command if not already in full functionality mode. If the power-up is sent while already in full functionality mode, they get rebooted and reseted. With this changes, plugins can check whether they need the power-up and ask the generic gsm code base to skip the command or not. By default, power-up command (if any given) is never skipped. --- src/mm-generic-gsm.c | 34 ++++++++++++++++++++++++++++------ src/mm-generic-gsm.h | 11 ++++++++++- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index d814c57c..34ab8233 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -1540,6 +1540,27 @@ enable_done (MMAtSerialPort *port, info); } +static void +enable_power_up_check_needed_done (MMModem *self, + guint32 needed, + GError *error, + gpointer user_data) +{ + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + char *cmd = NULL; + + if (needed) + g_object_get (G_OBJECT (self), MM_GENERIC_GSM_POWER_UP_CMD, &cmd, NULL); + else + mm_dbg ("Power-up not needed, skipping..."); + + if (cmd && strlen (cmd)) + mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (priv->primary), cmd, 5, enable_done, user_data); + else + enable_done (MM_AT_SERIAL_PORT (priv->primary), NULL, NULL, user_data); + g_free (cmd); +} + static void init_done (MMAtSerialPort *port, GString *response, @@ -1573,12 +1594,13 @@ init_done (MMAtSerialPort *port, mm_at_serial_port_queue_command (port, cmd, 2, NULL, NULL); g_free (cmd); - g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_POWER_UP_CMD, &cmd, NULL); - if (cmd && strlen (cmd)) - mm_at_serial_port_queue_command (port, cmd, 5, enable_done, user_data); + /* Plugins can now check if they need the power up command or not */ + if (MM_GENERIC_GSM_GET_CLASS (info->modem)->do_enable_power_up_check_needed) + MM_GENERIC_GSM_GET_CLASS (info->modem)->do_enable_power_up_check_needed (MM_GENERIC_GSM (info->modem), + enable_power_up_check_needed_done, + info); else - enable_done (port, NULL, NULL, user_data); - g_free (cmd); + enable_power_up_check_needed_done (info->modem, TRUE, NULL, info); } static void @@ -4875,7 +4897,7 @@ ussd_send_done (MMAtSerialPort *port, ussd_update_state (MM_GENERIC_GSM (info->modem), MM_MODEM_GSM_USSD_STATE_IDLE); } - /* Otherwise if no error wait for the response to show up via the + /* Otherwise if no error wait for the response to show up via the * unsolicited response code. */ } diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h index 57b65bf8..73a03ad2 100644 --- a/src/mm-generic-gsm.h +++ b/src/mm-generic-gsm.h @@ -90,7 +90,15 @@ typedef struct { * encountered during the process and the MMCallbackInfo created from the * callback and user_data passed in here. */ - void (*do_enable) (MMGenericGsm *self, MMModemFn callback, gpointer user_data); + void (*do_enable) (MMGenericGsm *self, + MMModemFn callback, + gpointer user_data); + + /* Called before issuing the power-up command, to check whether it should + * really be issued or not. */ + void (*do_enable_power_up_check_needed) (MMGenericGsm *self, + MMModemUIntFn callback, + gpointer user_data); /* Called after the generic class has attempted to power up the modem. * Subclasses can handle errors here if they know the device supports their @@ -143,6 +151,7 @@ typedef struct { void (*get_sim_iccid) (MMGenericGsm *self, MMModemStringFn callback, gpointer user_data); + } MMGenericGsmClass; GType mm_generic_gsm_get_type (void); From 255525a5a2d499ef7b4d01cea660502bd1dff6a5 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Tue, 21 Jun 2011 14:39:23 +0200 Subject: [PATCH 2/8] wavecom: do not send power-up command if not needed --- plugins/mm-modem-wavecom-gsm.c | 108 ++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 43 deletions(-) diff --git a/plugins/mm-modem-wavecom-gsm.c b/plugins/mm-modem-wavecom-gsm.c index c66637cf..652511a0 100644 --- a/plugins/mm-modem-wavecom-gsm.c +++ b/plugins/mm-modem-wavecom-gsm.c @@ -869,7 +869,7 @@ set_highest_ms_class_cb (MMAtSerialPort *port, } /* All done without errors! */ - mm_dbg ("[5/5] All done"); + mm_dbg ("[4/4] All done"); enable_complete (MM_GENERIC_GSM (info->modem), NULL, info); } @@ -975,7 +975,7 @@ get_current_ms_class_cb (MMAtSerialPort *port, } /* Next, set highest mobile station class possible */ - mm_dbg ("[4/5] Ensuring highest MS class..."); + mm_dbg ("[3/4] Ensuring highest MS class..."); set_highest_ms_class (port, info); } @@ -1039,47 +1039,10 @@ get_supported_ms_classes_cb (MMAtSerialPort *port, } /* Next, query for current MS class */ - mm_dbg ("[3/5] Getting current MS class..."); + mm_dbg ("[2/4] Getting current MS class..."); mm_at_serial_port_queue_command (port, "+CGCLASS?", 3, get_current_ms_class_cb, info); } -static void -get_current_functionality_status_cb (MMAtSerialPort *port, - GString *response, - GError *error, - gpointer user_data) -{ - MMCallbackInfo *info = user_data; - const gchar *p; - GError *inner_error; - - /* If the modem has already been removed, return without - * scheduling callback */ - if (mm_callback_info_check_modem_removed (info)) - return; - - if (error) { - enable_complete (MM_GENERIC_GSM (info->modem), error, info); - return; - } - - p = mm_strip_tag (response->str, "+CFUN:"); - if (!p || *p != '1') { - /* Reported functionality status MUST be '1'. Otherwise, RF is probably - * switched off. */ - inner_error = g_error_new (MM_MODEM_ERROR, - MM_MODEM_ERROR_GENERAL, - "Unexpected functionality status: '%c'. ", - p ? *p :' '); - enable_complete (MM_GENERIC_GSM (info->modem), inner_error, info); - g_error_free (inner_error); - } - - /* Nex, query for supported MS classes */ - mm_dbg ("[2/5] Getting supported MS classes..."); - mm_at_serial_port_queue_command (port, "+CGCLASS=?", 3, get_supported_ms_classes_cb, info); -} - static void do_enable_power_up_done (MMGenericGsm *gsm, GString *response, @@ -1107,9 +1070,67 @@ do_enable_power_up_done (MMGenericGsm *gsm, return; } - /* Next, get current functionality status */ - mm_dbg ("[1/5] Getting current functionality status..."); - mm_at_serial_port_queue_command (port, "+CFUN?", 3, get_current_functionality_status_cb, info); + mm_dbg ("[1/4] Getting supported MS classes..."); + mm_at_serial_port_queue_command (port, "+CGCLASS=?", 3, get_supported_ms_classes_cb, info); +} + +static void +get_current_functionality_status_cb (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + guint needed = FALSE; + + /* If the modem has already been removed, return without + * scheduling callback */ + if (mm_callback_info_check_modem_removed (info)) + return; + + /* On error, just assume we don't need the power-up command */ + if (!error) { + const gchar *p; + + p = mm_strip_tag (response->str, "+CFUN:"); + if (p && *p == '1') { + /* If reported functionality status is '1', then we do not need to + * issue the power-up command. Otherwise, do it. */ + mm_dbg ("Already in full functionality status, skipping power-up command"); + } else { + needed = TRUE; + mm_warn ("Not in full functionality status, power-up command is needed. " + "Note that it may reboot the modem."); + } + } else + mm_warn ("Failed checking if power-up command is needed: '%s'. " + "Will assume it isn't.", + error->message); + + /* Set result and schedule */ + mm_callback_info_set_result (info, + GUINT_TO_POINTER (needed), + NULL); + mm_callback_info_schedule (info); +} + +static void +do_enable_power_up_check_needed (MMGenericGsm *self, + MMModemUIntFn callback, + gpointer user_data) +{ + MMAtSerialPort *primary; + MMCallbackInfo *info; + + info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data); + + /* Get port */ + primary = mm_generic_gsm_get_at_port (self, MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + /* Get current functionality status */ + mm_dbg ("Getting current functionality status..."); + mm_at_serial_port_queue_command (primary, "+CFUN?", 3, get_current_functionality_status_cb, info); } /*****************************************************************************/ @@ -1158,6 +1179,7 @@ mm_modem_wavecom_gsm_class_init (MMModemWavecomGsmClass *klass) MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD, MM_GENERIC_GSM_FLOW_CONTROL_CMD); + gsm_class->do_enable_power_up_check_needed = do_enable_power_up_check_needed; gsm_class->do_enable_power_up_done = do_enable_power_up_done; gsm_class->set_allowed_mode = set_allowed_mode; gsm_class->get_allowed_mode = get_allowed_mode; From ab485bd66a3dfe4fdafe6425f48417997784be21 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Tue, 21 Jun 2011 14:41:56 +0200 Subject: [PATCH 3/8] wavecom: try to power-up without rebooting Using AT+CFUN=1,0 so that we request to avoid resetting (=0). Works properly when powering up after having put the modem in standby mode with AT+CFUN=4. Note that the power-up command will only be sent if the check to see if power-up is needed requests it. --- plugins/mm-modem-wavecom-gsm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/mm-modem-wavecom-gsm.c b/plugins/mm-modem-wavecom-gsm.c index 652511a0..dc541713 100644 --- a/plugins/mm-modem-wavecom-gsm.c +++ b/plugins/mm-modem-wavecom-gsm.c @@ -218,10 +218,10 @@ get_property (GObject *object, { switch (prop_id) { case MM_GENERIC_GSM_PROP_POWER_UP_CMD: - /* Wavecom doesn't like CFUN=1, it will reset the whole software stack, - * including the USB connection and therefore connection would get - * closed */ - g_value_set_string (value, ""); + /* Try to go to full functionality mode without rebooting the system. + * Works well if we previously switched off the power with CFUN=4 + */ + g_value_set_string (value, "+CFUN=1,0"); break; case MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD: /* Wavecom doesn't have XOFF/XON flow control, so we enable RTS/CTS */ From 34b5635f84798005e93a4be4c84ebd5dbe9f5212 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Tue, 21 Jun 2011 14:49:38 +0200 Subject: [PATCH 4/8] wavecom: enable power-off command to go to sleep/standby mode AT+CFUN=4 will be used to go to standby mode. --- plugins/mm-modem-wavecom-gsm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/mm-modem-wavecom-gsm.c b/plugins/mm-modem-wavecom-gsm.c index dc541713..3bfcdbe6 100644 --- a/plugins/mm-modem-wavecom-gsm.c +++ b/plugins/mm-modem-wavecom-gsm.c @@ -227,6 +227,11 @@ get_property (GObject *object, /* Wavecom doesn't have XOFF/XON flow control, so we enable RTS/CTS */ g_value_set_string (value, "+IFC=2,2"); break; + case MM_GENERIC_GSM_PROP_POWER_DOWN_CMD: + /* Use AT+CFUN=4 for power down. It will stop the RF (IMSI detach), and + * keeps access to the SIM */ + g_value_set_string (value, "+CFUN=4"); + break; default: break; } @@ -1179,6 +1184,10 @@ mm_modem_wavecom_gsm_class_init (MMModemWavecomGsmClass *klass) MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD, MM_GENERIC_GSM_FLOW_CONTROL_CMD); + g_object_class_override_property (object_class, + MM_GENERIC_GSM_PROP_POWER_DOWN_CMD, + MM_GENERIC_GSM_POWER_DOWN_CMD); + gsm_class->do_enable_power_up_check_needed = do_enable_power_up_check_needed; gsm_class->do_enable_power_up_done = do_enable_power_up_done; gsm_class->set_allowed_mode = set_allowed_mode; From 56db81890120e63f251b899b0eac66dc8941d411 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Tue, 21 Jun 2011 15:07:16 +0200 Subject: [PATCH 5/8] sierra: do not send power-up command if not needed --- plugins/mm-modem-sierra-gsm.c | 60 +++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/plugins/mm-modem-sierra-gsm.c b/plugins/mm-modem-sierra-gsm.c index 6d4e4d5a..5352761f 100644 --- a/plugins/mm-modem-sierra-gsm.c +++ b/plugins/mm-modem-sierra-gsm.c @@ -25,6 +25,7 @@ #include "mm-modem-simple.h" #include "mm-callback-info.h" #include "mm-modem-helpers.h" +#include "mm-log.h" static void modem_init (MMModem *modem_class); static void modem_simple_init (MMModemSimple *class); @@ -391,6 +392,64 @@ real_do_enable_power_up_done (MMGenericGsm *gsm, priv->enable_wait_id = g_timeout_add_seconds (10, sierra_enabled, info); } +static void +get_current_functionality_status_cb (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + guint needed = FALSE; + + /* If the modem has already been removed, return without + * scheduling callback */ + if (mm_callback_info_check_modem_removed (info)) + return; + + /* On error, just assume we don't need the power-up command */ + if (!error) { + const gchar *p; + + p = mm_strip_tag (response->str, "+CFUN:"); + if (p && *p == '1') { + /* If reported functionality status is '1', then we do not need to + * issue the power-up command. Otherwise, do it. */ + mm_dbg ("Already in full functionality status, skipping power-up command"); + } else { + needed = TRUE; + mm_warn ("Not in full functionality status, power-up command is needed."); + } + } else + mm_warn ("Failed checking if power-up command is needed: '%s'. " + "Will assume it isn't.", + error->message); + + /* Set result and schedule */ + mm_callback_info_set_result (info, + GUINT_TO_POINTER (needed), + NULL); + mm_callback_info_schedule (info); +} + +static void +do_enable_power_up_check_needed (MMGenericGsm *self, + MMModemUIntFn callback, + gpointer user_data) +{ + MMAtSerialPort *primary; + MMCallbackInfo *info; + + info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data); + + /* Get port */ + primary = mm_generic_gsm_get_at_port (self, MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + /* Get current functionality status */ + mm_dbg ("Getting current functionality status..."); + mm_at_serial_port_queue_command (primary, "+CFUN?", 3, get_current_functionality_status_cb, info); +} + static gboolean grab_port (MMModem *modem, const char *subsys, @@ -689,6 +748,7 @@ mm_modem_sierra_gsm_class_init (MMModemSierraGsmClass *klass) g_type_class_add_private (object_class, sizeof (MMModemSierraGsmPrivate)); object_class->dispose = dispose; + gsm_class->do_enable_power_up_check_needed = do_enable_power_up_check_needed; gsm_class->do_enable_power_up_done = real_do_enable_power_up_done; gsm_class->set_allowed_mode = set_allowed_mode; gsm_class->get_allowed_mode = get_allowed_mode; From eae5d6c41be6652bac384340c47d274164007ebb Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Wed, 22 Jun 2011 13:01:17 +0200 Subject: [PATCH 6/8] cinterion: enable power-off command to go to sleep/standby mode AT+CFUN=4 will be used when available to go to standby mode. If not supported, (as in EGS5) AT+CFUN=7 will be used instead, which enables a CYCLIC SLEEP mode. Flow control setup was updated to RCS/CTS so that waking up from sleep mode works properly. --- plugins/mm-modem-cinterion-gsm.c | 97 ++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 5 deletions(-) diff --git a/plugins/mm-modem-cinterion-gsm.c b/plugins/mm-modem-cinterion-gsm.c index 56a6b007..34a5d6dc 100644 --- a/plugins/mm-modem-cinterion-gsm.c +++ b/plugins/mm-modem-cinterion-gsm.c @@ -66,6 +66,9 @@ typedef struct { /* Bitmask for currently active bands */ guint32 current_bands; + + /* Command to go into sleep mode */ + gchar *sleep_mode_cmd; } MMModemCinterionGsmPrivate; /* Setup relationship between the band bitmask in the modem and the bitmask @@ -833,6 +836,55 @@ enable_complete (MMGenericGsm *gsm, mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); } +static void +get_supported_functionality_status_cb (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + MMModemCinterionGsmPrivate *priv; + + /* If the modem has already been removed, return without + * scheduling callback */ + if (mm_callback_info_check_modem_removed (info)) + return; + + if (error) { + enable_complete (MM_GENERIC_GSM (info->modem), error, info); + return; + } + + priv = MM_MODEM_CINTERION_GSM_GET_PRIVATE (info->modem); + + /* We need to get which power-off command to use to put the modem in low + * power mode (with serial port open for AT commands, but with RF switched + * off). According to the documentation of various Cinterion modems, some + * support AT+CFUN=4 (HC25) and those which don't support it can use + * AT+CFUN=7 (CYCLIC SLEEP mode with 2s timeout after last character + * received in the serial port). + * + * So, just look for '4' in the reply; if not found, look for '7', and if + * not found, report warning and don't use any. + */ + + g_free (priv->sleep_mode_cmd); + if (strstr (response->str, "4") != NULL) { + mm_dbg ("Device supports CFUN=4 sleep mode"); + priv->sleep_mode_cmd = g_strdup ("+CFUN=4"); + } else if (strstr (response->str, "7") != NULL) { + mm_dbg ("Device supports CFUN=7 sleep mode"); + priv->sleep_mode_cmd = g_strdup ("+CFUN=7"); + } else { + mm_warn ("Unknown functionality mode to go into sleep mode"); + priv->sleep_mode_cmd = NULL; + } + + /* All done without errors! */ + mm_dbg ("[3/3] All done"); + enable_complete (MM_GENERIC_GSM (info->modem), NULL, info); +} + static void get_supported_networks_cb (MMAtSerialPort *port, GString *response, @@ -841,7 +893,6 @@ get_supported_networks_cb (MMAtSerialPort *port, { MMCallbackInfo *info = user_data; MMModemCinterionGsmPrivate *priv; - GError *inner_error = NULL; /* If the modem has already been removed, return without * scheduling callback */ @@ -880,17 +931,22 @@ get_supported_networks_cb (MMAtSerialPort *port, if (!priv->only_geran && !priv->only_utran && !priv->both_geran_utran) { + GError *inner_error = NULL; + mm_warn ("Invalid list of supported networks: '%s'", response->str); inner_error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Invalid list of supported networks: '%s'", response->str); + enable_complete (MM_GENERIC_GSM (info->modem), inner_error, info); + g_error_free (inner_error); + return; } - enable_complete (MM_GENERIC_GSM (info->modem), inner_error, info); - if (inner_error) - g_error_free (inner_error); + /* Next, check which supported functionality modes are available */ + mm_dbg ("[2/3] Getting list of supported functionality status..."); + mm_at_serial_port_queue_command (port, "+CFUN=?", 3, get_supported_functionality_status_cb, info); } static void @@ -915,7 +971,8 @@ do_enable_power_up_done (MMGenericGsm *gsm, return; } - /* List supported networks */ + /* First, list supported networks */ + mm_dbg ("[1/3] Getting list of supported networks..."); mm_at_serial_port_queue_command (port, "+WS46=?", 3, get_supported_networks_cb, info); } @@ -934,7 +991,13 @@ get_property (GObject *object, GValue *value, GParamSpec *pspec) { + MMModemCinterionGsmPrivate *priv = MM_MODEM_CINTERION_GSM_GET_PRIVATE (object); + switch (prop_id) { + case MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD: + /* We need to enable RTS/CTS so that CYCLIC SLEEP mode works */ + g_value_set_string (value, "\\Q3"); + break; case MM_GENERIC_GSM_PROP_SMS_INDICATION_ENABLE_CMD: /* AT+CNMO=,[[,[,[,]]]] * but should be either not set, or equal to 1; @@ -956,11 +1019,25 @@ get_property (GObject *object, * */ g_value_set_string (value, "+CMER=3,0,0,2"); break; + case MM_GENERIC_GSM_PROP_POWER_DOWN_CMD: + /* Use the value computed before, if any. */ + g_value_set_string (value, priv->sleep_mode_cmd ? priv->sleep_mode_cmd : ""); + break; default: break; } } +static void +finalize (GObject *object) +{ + MMModemCinterionGsmPrivate *priv = MM_MODEM_CINTERION_GSM_GET_PRIVATE (object); + + g_free (priv->sleep_mode_cmd); + + G_OBJECT_CLASS (mm_modem_cinterion_gsm_parent_class)->finalize (object); +} + /*****************************************************************************/ static void @@ -990,11 +1067,17 @@ mm_modem_cinterion_gsm_class_init (MMModemCinterionGsmClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass); + mm_modem_cinterion_gsm_parent_class = g_type_class_peek_parent (klass); g_type_class_add_private (object_class, sizeof (MMModemCinterionGsmPrivate)); + object_class->finalize = finalize; object_class->get_property = get_property; object_class->set_property = set_property; + g_object_class_override_property (object_class, + MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD, + MM_GENERIC_GSM_FLOW_CONTROL_CMD); + g_object_class_override_property (object_class, MM_GENERIC_GSM_PROP_SMS_INDICATION_ENABLE_CMD, MM_GENERIC_GSM_SMS_INDICATION_ENABLE_CMD); @@ -1007,6 +1090,10 @@ mm_modem_cinterion_gsm_class_init (MMModemCinterionGsmClass *klass) MM_GENERIC_GSM_PROP_CMER_ENABLE_CMD, MM_GENERIC_GSM_CMER_ENABLE_CMD); + g_object_class_override_property (object_class, + MM_GENERIC_GSM_PROP_POWER_DOWN_CMD, + MM_GENERIC_GSM_POWER_DOWN_CMD); + gsm_class->do_enable_power_up_done = do_enable_power_up_done; gsm_class->set_allowed_mode = set_allowed_mode; gsm_class->get_allowed_mode = get_allowed_mode; From 39abb023ed180d03ea8324285116e228b46cd411 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Wed, 22 Jun 2011 15:53:37 +0200 Subject: [PATCH 7/8] serial: new property to enable RTS/CTS flow control --- src/mm-serial-port.c | 21 +++++++++++++++++++++ src/mm-serial-port.h | 1 + 2 files changed, 22 insertions(+) diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c index 70e33672..617da5a3 100644 --- a/src/mm-serial-port.c +++ b/src/mm-serial-port.c @@ -45,6 +45,7 @@ enum { PROP_SEND_DELAY, PROP_FD, PROP_SPEW_CONTROL, + PROP_RTS_CTS, LAST_PROP }; @@ -78,6 +79,7 @@ typedef struct { guint stopbits; guint64 send_delay; gboolean spew_control; + gboolean rts_cts; guint queue_id; guint watch_id; @@ -1059,6 +1061,7 @@ get_speed (MMSerialPort *self, speed_t *speed, GError **error) static gboolean set_speed (MMSerialPort *self, speed_t speed, GError **error) { + MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self); struct termios options; int fd, count = 4; gboolean success = FALSE; @@ -1079,6 +1082,10 @@ set_speed (MMSerialPort *self, speed_t speed, GError **error) cfsetospeed (&options, speed); options.c_cflag |= (CLOCAL | CREAD); + /* Configure flow control as well here */ + if (priv->rts_cts) + options.c_cflag |= (CRTSCTS); + while (count-- > 0) { if (tcsetattr (fd, TCSANOW, &options) == 0) { success = TRUE; @@ -1311,6 +1318,9 @@ set_property (GObject *object, guint prop_id, case PROP_SPEW_CONTROL: priv->spew_control = g_value_get_boolean (value); break; + case PROP_RTS_CTS: + priv->rts_cts = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1345,6 +1355,9 @@ get_property (GObject *object, guint prop_id, case PROP_SPEW_CONTROL: g_value_set_boolean (value, priv->spew_control); break; + case PROP_RTS_CTS: + g_value_set_boolean (value, priv->rts_cts); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1455,6 +1468,14 @@ mm_serial_port_class_init (MMSerialPortClass *klass) FALSE, G_PARAM_READWRITE)); + g_object_class_install_property + (object_class, PROP_RTS_CTS, + g_param_spec_boolean (MM_SERIAL_PORT_RTS_CTS, + "RTSCTS", + "Enable RTS/CTS flow control", + FALSE, + G_PARAM_READWRITE)); + /* Signals */ signals[BUFFER_FULL] = g_signal_new ("buffer-full", diff --git a/src/mm-serial-port.h b/src/mm-serial-port.h index e9997a58..a9f34402 100644 --- a/src/mm-serial-port.h +++ b/src/mm-serial-port.h @@ -35,6 +35,7 @@ #define MM_SERIAL_PORT_PARITY "parity" #define MM_SERIAL_PORT_STOPBITS "stopbits" #define MM_SERIAL_PORT_SEND_DELAY "send-delay" +#define MM_SERIAL_PORT_RTS_CTS "rts-cts" #define MM_SERIAL_PORT_FD "fd" /* Construct-only */ #define MM_SERIAL_PORT_SPEW_CONTROL "spew-control" /* Construct-only */ From 7e69d2cf307efdb4ddec5ef0eef9f6141bf8fa65 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Wed, 22 Jun 2011 16:00:58 +0200 Subject: [PATCH 8/8] cinterion: always try to use RTS/CTS flow control Otherwise, power-up after going to standby will not work properly --- plugins/mm-modem-cinterion-gsm.c | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/plugins/mm-modem-cinterion-gsm.c b/plugins/mm-modem-cinterion-gsm.c index 34a5d6dc..df10fdbf 100644 --- a/plugins/mm-modem-cinterion-gsm.c +++ b/plugins/mm-modem-cinterion-gsm.c @@ -27,9 +27,11 @@ #include "mm-serial-parsers.h" #include "mm-log.h" +static void modem_init (MMModem *modem_class); static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class); G_DEFINE_TYPE_EXTENDED (MMModemCinterionGsm, mm_modem_cinterion_gsm, MM_TYPE_GENERIC_GSM, 0, + G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init) G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_NETWORK, modem_gsm_network_init)) /* Mask of all bands supported in 2G devices */ @@ -135,6 +137,37 @@ mm_modem_cinterion_gsm_new (const char *device, NULL)); } +static gboolean +grab_port (MMModem *modem, + const char *subsys, + const char *name, + MMPortType suggested_type, + gpointer user_data, + GError **error) +{ + MMGenericGsm *gsm = MM_GENERIC_GSM (modem); + MMPortType ptype = MM_PORT_TYPE_IGNORED; + MMPort *port = NULL; + + if (suggested_type == MM_PORT_TYPE_UNKNOWN) { + if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY)) + ptype = MM_PORT_TYPE_PRIMARY; + else if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_SECONDARY)) + ptype = MM_PORT_TYPE_SECONDARY; + } else + ptype = suggested_type; + + port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error); + if (port && MM_IS_AT_SERIAL_PORT (port)) { + /* Set RTS/CTS flow control by default */ + g_object_set (G_OBJECT (port), + MM_SERIAL_PORT_RTS_CTS, TRUE, + NULL); + } + + return !!port; +} + static void convert_str_from_ucs2 (gchar **str) { @@ -1040,6 +1073,12 @@ finalize (GObject *object) /*****************************************************************************/ +static void +modem_init (MMModem *modem_class) +{ + modem_class->grab_port = grab_port; +} + static void modem_gsm_network_init (MMModemGsmNetwork *network_class) {