aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2011-06-30 19:48:23 +0200
committerAleksander Morgado <aleksander@lanedo.com>2011-06-30 19:48:23 +0200
commit7762d401e8201efc05d643b9da32f3e60a42c470 (patch)
treec1de587432ca1c0b1a766127aabbc14a77ac75a0
parent881f928c40f1460bcb03fae3eaf96b23f40fca3f (diff)
parent7e69d2cf307efdb4ddec5ef0eef9f6141bf8fa65 (diff)
Merge remote-tracking branch 'lanedo/power-up-check-needed'
-rw-r--r--plugins/mm-modem-cinterion-gsm.c136
-rw-r--r--plugins/mm-modem-sierra-gsm.c60
-rw-r--r--plugins/mm-modem-wavecom-gsm.c121
-rw-r--r--src/mm-generic-gsm.c34
-rw-r--r--src/mm-generic-gsm.h11
-rw-r--r--src/mm-serial-port.c21
-rw-r--r--src/mm-serial-port.h1
7 files changed, 327 insertions, 57 deletions
diff --git a/plugins/mm-modem-cinterion-gsm.c b/plugins/mm-modem-cinterion-gsm.c
index 56a6b007..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 */
@@ -66,6 +68,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
@@ -132,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)
{
@@ -834,6 +870,55 @@ enable_complete (MMGenericGsm *gsm,
}
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,
GError *error,
@@ -841,7 +926,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 +964,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 +1004,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 +1024,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=<mode>,[<mt>[,<bm>[,<ds>[,<bfr>]]]]
* but <bfr> should be either not set, or equal to 1;
@@ -956,14 +1052,34 @@ 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
+modem_init (MMModem *modem_class)
+{
+ modem_class->grab_port = grab_port;
+}
+
+static void
modem_gsm_network_init (MMModemGsmNetwork *network_class)
{
network_class->set_band = set_band;
@@ -990,12 +1106,18 @@ 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 +1129,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;
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;
diff --git a/plugins/mm-modem-wavecom-gsm.c b/plugins/mm-modem-wavecom-gsm.c
index c66637cf..3bfcdbe6 100644
--- a/plugins/mm-modem-wavecom-gsm.c
+++ b/plugins/mm-modem-wavecom-gsm.c
@@ -218,15 +218,20 @@ 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 */
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;
}
@@ -869,7 +874,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 +980,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,19 +1044,18 @@ 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)
+do_enable_power_up_done (MMGenericGsm *gsm,
+ GString *response,
+ GError *error,
+ MMCallbackInfo *info)
{
- MMCallbackInfo *info = user_data;
- const gchar *p;
- GError *inner_error;
+ MMAtSerialPort *port;
+ GError *inner_error = NULL;
/* If the modem has already been removed, return without
* scheduling callback */
@@ -1059,57 +1063,79 @@ get_current_functionality_status_cb (MMAtSerialPort *port,
return;
if (error) {
- enable_complete (MM_GENERIC_GSM (info->modem), error, info);
+ enable_complete (gsm, 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);
+ /* Get port */
+ port = mm_generic_gsm_get_best_at_port (gsm, &inner_error);
+ if (!port) {
+ enable_complete (gsm, inner_error, info);
g_error_free (inner_error);
+ return;
}
- /* Nex, query for supported MS classes */
- mm_dbg ("[2/5] Getting supported MS classes...");
+ 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
-do_enable_power_up_done (MMGenericGsm *gsm,
- GString *response,
- GError *error,
- MMCallbackInfo *info)
+get_current_functionality_status_cb (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
- MMAtSerialPort *port;
- GError *inner_error = NULL;
+ 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;
- if (error) {
- enable_complete (gsm, error, 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 */
- port = mm_generic_gsm_get_best_at_port (gsm, &inner_error);
- if (!port) {
- enable_complete (gsm, inner_error, info);
- g_error_free (inner_error);
- return;
- }
+ primary = mm_generic_gsm_get_at_port (self, MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
- /* 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);
+ /* 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 +1184,11 @@ 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;
gsm_class->get_allowed_mode = get_allowed_mode;
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index c3c3d472..95540590 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -1541,6 +1541,27 @@ enable_done (MMAtSerialPort *port,
}
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,
GError *error,
@@ -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);
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 */