[PATCH v2] broadband-bearer: once connected, set flow control settings
Dan Williams
dcbw at redhat.com
Mon Apr 17 16:54:12 UTC 2017
On Sun, 2017-04-09 at 14:14 +0200, Aleksander Morgado wrote:
> During modem initialization we detected the flow control settings
> supported by the modem, and selected the best one to use from them,
> notifying it to the device via AT+IFC. The device was therefore
> instructed to use that flow control setting for data transmission in
> the TTY (i.e. not during AT control commands).
>
> The missing thing was to also configure ourselves our end of the
> serial port with the same flow control settings when getting into
> data
> mode. By doing it ourselves, we avoid requiring any explicit setting
> in pppd for flow control; pppd can assume the flow control settings
> are already the expected ones.
>
> Worth noting that all this setup is completely ignored for TTYs
> exposed directly via USB.
>
> https://bugs.freedesktop.org/show_bug.cgi?id=100394
> ---
>
> Hey Dan and everyone,
>
> I made the flow control setting a readable property in the Modem
> object, and a RW property in the Bearer object. The property is
> inherited by the bearer object when it is created, i.e. in
> mm_broadband_bearer_new() we just read the property from the modem
> and we set it in the bearer creation.
>
> I thought of g_object_bind_property()-ing them whenever the "modem"
> object was set as property in the "bearer" object, but then realized
> that happens in "MMBaseBearer" level not in "MMBroadbandBearer", so
> decided not to complicate it more; especially since the property
> won't change any more.
>
> What do you think?
Looks OK to me, though if we're not exposing the flow control via the
D-Bus API on the Modem object, should we just not bother making it a
property there? It's not used anywhere yet...
Dan
> ---
> .gitignore | 2 +
> src/Makefile.am | 28 +++++++++++
> src/mm-broadband-bearer.c | 125
> ++++++++++++++++++++++++++++++++++++++++++++--
> src/mm-broadband-bearer.h | 3 ++
> src/mm-broadband-modem.c | 49 ++++++++++++++----
> src/mm-broadband-modem.h | 3 ++
> src/mm-modem-helpers.h | 2 +-
> 7 files changed, 196 insertions(+), 16 deletions(-)
>
> diff --git a/.gitignore b/.gitignore
> index 03c7d52e..9e79d258 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -48,6 +48,8 @@ Makefile.in
> /src/mm-daemon-enums-types.h
> /src/mm-port-enums-types.c
> /src/mm-port-enums-types.h
> +/src/mm-helper-enums-types.c
> +/src/mm-helper-enums-types.h
> /src/mm-marshal.[ch]
> /src/tests/test-modem-helpers
> /src/tests/test-modem-helpers-qmi
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 91b4e17a..13481e96 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -67,6 +67,28 @@ EXTRA_DIST += $(udevrules_DATA)
>
> noinst_LTLIBRARIES += libhelpers.la
>
> +HELPER_ENUMS_INPUTS = \
> + $(srcdir)/mm-modem-helpers.h \
> + $(NULL)
> +
> +HELPER_ENUMS_GENERATED = \
> + mm-helper-enums-types.h \
> + mm-helper-enums-types.c \
> + $(NULL)
> +
> +mm-helper-enums-types.h: Makefile.am $(HELPER_ENUMS_INPUTS)
> $(top_srcdir)/build-aux/mm-enums-template.h
> + $(AM_V_GEN) $(GLIB_MKENUMS) \
> + --fhead "#include \"mm-modem-helpers.h\"\n#ifndef
> __MM_HELPER_ENUMS_TYPES_H__\n#define __MM_HELPER_ENUMS_TYPES_H__\n" \
> + --template $(top_srcdir)/build-aux/mm-enums-
> template.h \
> + --ftail "#endif /* __MM_HELPER_ENUMS_TYPES_H__ */\n"
> \
> + $(HELPER_ENUMS_INPUTS) > $@
> +
> +mm-helper-enums-types.c: Makefile.am $(top_srcdir)/build-aux/mm-
> enums-template.c mm-helper-enums-types.h
> + $(AM_V_GEN) $(GLIB_MKENUMS) \
> + --fhead "#include \"mm-helper-enums-types.h\"" \
> + --template $(top_srcdir)/build-aux/mm-enums-
> template.c \
> + $(HELPER_ENUMS_INPUTS) > $@
> +
> libhelpers_la_SOURCES = \
> mm-error-helpers.c \
> mm-error-helpers.h \
> @@ -82,6 +104,8 @@ libhelpers_la_SOURCES = \
> mm-sms-part-cdma.c \
> $(NULL)
>
> +nodist_libhelpers_la_SOURCES = $(HELPER_ENUMS_GENERATED)
> +
> if WITH_QMI
> libhelpers_la_SOURCES += \
> mm-modem-helpers-qmi.c \
> @@ -96,6 +120,10 @@ libhelpers_la_SOURCES += \
> $(NULL)
> endif
>
> +# Request to build enum types before anything else
> +BUILT_SOURCES += $(HELPER_ENUMS_GENERATED)
> +CLEANFILES += $(HELPER_ENUMS_GENERATED)
> +
> ####################################################################
> ############
> # kerneldevice library
> ####################################################################
> ############
> diff --git a/src/mm-broadband-bearer.c b/src/mm-broadband-bearer.c
> index 0565eee3..ac701733 100644
> --- a/src/mm-broadband-bearer.c
> +++ b/src/mm-broadband-bearer.c
> @@ -35,6 +35,7 @@
> #include "mm-log.h"
> #include "mm-modem-helpers.h"
> #include "mm-port-enums-types.h"
> +#include "mm-helper-enums-types.h"
>
> static void async_initable_iface_init (GAsyncInitableIface *iface);
>
> @@ -48,6 +49,14 @@ typedef enum {
> CONNECTION_TYPE_CDMA,
> } ConnectionType;
>
> +enum {
> + PROP_0,
> + PROP_FLOW_CONTROL,
> + PROP_LAST
> +};
> +
> +static GParamSpec *properties[PROP_LAST];
> +
> struct _MMBroadbandBearerPrivate {
> /*-- Common stuff --*/
> /* Data port used when modem is connected */
> @@ -55,6 +64,9 @@ struct _MMBroadbandBearerPrivate {
> /* Current connection type */
> ConnectionType connection_type;
>
> + /* PPP specific */
> + MMFlowControl flow_control;
> +
> /*-- 3GPP specific --*/
> /* CID of the PDP context */
> guint cid;
> @@ -254,6 +266,20 @@ dial_cdma_ready (MMBaseModem *modem,
> return;
> }
>
> + /* Configure flow control to use while connected */
> + if (ctx->self->priv->flow_control != MM_FLOW_CONTROL_NONE) {
> + gchar *flow_control_str;
> +
> + flow_control_str = mm_flow_control_build_string_from_mask
> (ctx->self->priv->flow_control);
> + mm_dbg ("[%s] Setting flow control: %s", mm_port_get_device
> (ctx->data), flow_control_str);
> + g_free (flow_control_str);
> +
> + if (!mm_port_serial_set_flow_control (MM_PORT_SERIAL (ctx-
> >data), ctx->self->priv->flow_control, &error)) {
> + mm_warn ("Couldn't set flow control settings: %s",
> error->message);
> + g_clear_error (&error);
> + }
> + }
> +
> /* The ATD command has succeeded, and therefore the TTY is in
> data mode now.
> * Instead of waiting for setting the port as connected later in
> * connect_succeeded(), we do it right away so that we stop our
> polling. */
> @@ -557,6 +583,8 @@ atd_ready (MMBaseModem *modem,
> GAsyncResult *res,
> Dial3gppContext *ctx)
> {
> + GError *error = NULL;
> +
> /* DO NOT check for cancellable here. If we got here without
> errors, the
> * bearer is really connected and therefore we need to reflect
> that in
> * the state machine. */
> @@ -576,6 +604,20 @@ atd_ready (MMBaseModem *modem,
> return;
> }
>
> + /* Configure flow control to use while connected */
> + if (ctx->self->priv->flow_control != MM_FLOW_CONTROL_NONE) {
> + gchar *flow_control_str;
> +
> + flow_control_str = mm_flow_control_build_string_from_mask
> (ctx->self->priv->flow_control);
> + mm_dbg ("[%s] Setting flow control: %s", mm_port_get_device
> (MM_PORT (ctx->dial_port)), flow_control_str);
> + g_free (flow_control_str);
> +
> + if (!mm_port_serial_set_flow_control (MM_PORT_SERIAL (ctx-
> >dial_port), ctx->self->priv->flow_control, &error)) {
> + mm_warn ("Couldn't set flow control settings: %s",
> error->message);
> + g_clear_error (&error);
> + }
> + }
> +
> /* The ATD command has succeeded, and therefore the TTY is in
> data mode now.
> * Instead of waiting for setting the port as connected later in
> * connect_succeeded(), we do it right away so that we stop our
> polling. */
> @@ -1455,6 +1497,16 @@ data_flash_cdma_ready (MMPortSerial *data,
>
> mm_port_serial_flash_finish (data, res, &error);
>
> + /* Cleanup flow control */
> + if (ctx->self->priv->flow_control != MM_FLOW_CONTROL_NONE) {
> + GError *flow_control_error = NULL;
> +
> + if (!mm_port_serial_set_flow_control (MM_PORT_SERIAL (data),
> MM_FLOW_CONTROL_NONE, &flow_control_error)) {
> + mm_dbg ("Couldn't reset flow control settings: %s",
> flow_control_error->message);
> + g_clear_error (&flow_control_error);
> + }
> + }
> +
> /* We kept the serial port open during connection, now we close
> that open
> * count */
> mm_port_serial_close (data);
> @@ -1572,6 +1624,16 @@ data_flash_3gpp_ready (MMPortSerial *data,
>
> mm_port_serial_flash_finish (data, res, &error);
>
> + /* Cleanup flow control */
> + if (ctx->self->priv->flow_control != MM_FLOW_CONTROL_NONE) {
> + GError *flow_control_error = NULL;
> +
> + if (!mm_port_serial_set_flow_control (MM_PORT_SERIAL (data),
> MM_FLOW_CONTROL_NONE, &flow_control_error)) {
> + mm_dbg ("Couldn't reset flow control settings: %s",
> flow_control_error->message);
> + g_clear_error (&flow_control_error);
> + }
> + }
> +
> /* We kept the serial port open during connection, now we close
> that open
> * count */
> mm_port_serial_close (data);
> @@ -2252,18 +2314,62 @@ mm_broadband_bearer_new (MMBroadbandModem
> *modem,
> GAsyncReadyCallback callback,
> gpointer user_data)
> {
> + MMFlowControl flow_control;
> +
> + /* Inherit flow control from modem object directly */
> + g_object_get (modem,
> + MM_BROADBAND_MODEM_FLOW_CONTROL, &flow_control,
> + NULL);
> +
> g_async_initable_new_async (
> MM_TYPE_BROADBAND_BEARER,
> G_PRIORITY_DEFAULT,
> cancellable,
> callback,
> user_data,
> - MM_BASE_BEARER_MODEM, modem,
> - MM_BASE_BEARER_CONFIG, properties,
> + MM_BASE_BEARER_MODEM, modem,
> + MM_BASE_BEARER_CONFIG, properties,
> + MM_BROADBAND_BEARER_FLOW_CONTROL, flow_control,
> NULL);
> }
>
> static void
> +set_property (GObject *object,
> + guint prop_id,
> + const GValue *value,
> + GParamSpec *pspec)
> +{
> + MMBroadbandBearer *self = MM_BROADBAND_BEARER (object);
> +
> + switch (prop_id) {
> + case PROP_FLOW_CONTROL:
> + self->priv->flow_control = g_value_get_flags (value);
> + break;
> + default:
> + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
> + break;
> + }
> +}
> +
> +static void
> +get_property (GObject *object,
> + guint prop_id,
> + GValue *value,
> + GParamSpec *pspec)
> +{
> + MMBroadbandBearer *self = MM_BROADBAND_BEARER (object);
> +
> + switch (prop_id) {
> + case PROP_FLOW_CONTROL:
> + g_value_set_flags (value, self->priv->flow_control);
> + break;
> + default:
> + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
> + break;
> + }
> +}
> +
> +static void
> mm_broadband_bearer_init (MMBroadbandBearer *self)
> {
> /* Initialize private data */
> @@ -2273,6 +2379,7 @@ mm_broadband_bearer_init (MMBroadbandBearer
> *self)
>
> /* Set defaults */
> self->priv->connection_type = CONNECTION_TYPE_NONE;
> + self->priv->flow_control = MM_FLOW_CONTROL_NONE;
> }
>
> static void
> @@ -2300,8 +2407,9 @@ mm_broadband_bearer_class_init
> (MMBroadbandBearerClass *klass)
>
> g_type_class_add_private (object_class, sizeof
> (MMBroadbandBearerPrivate));
>
> - /* Virtual methods */
> - object_class->dispose = dispose;
> + object_class->get_property = get_property;
> + object_class->set_property = set_property;
> + object_class->dispose = dispose;
>
> base_bearer_class->connect = connect;
> base_bearer_class->connect_finish = connect_finish;
> @@ -2325,4 +2433,13 @@ mm_broadband_bearer_class_init
> (MMBroadbandBearerClass *klass)
> klass->disconnect_3gpp_finish = detailed_disconnect_finish;
> klass->disconnect_cdma = disconnect_cdma;
> klass->disconnect_cdma_finish = detailed_disconnect_finish;
> +
> + properties[PROP_FLOW_CONTROL] =
> + g_param_spec_flags (MM_BROADBAND_BEARER_FLOW_CONTROL,
> + "Flow control",
> + "Flow control settings to use during
> connection",
> + MM_TYPE_FLOW_CONTROL,
> + MM_FLOW_CONTROL_NONE,
> + G_PARAM_READWRITE);
> + g_object_class_install_property (object_class,
> PROP_FLOW_CONTROL, properties[PROP_FLOW_CONTROL]);
> }
> diff --git a/src/mm-broadband-bearer.h b/src/mm-broadband-bearer.h
> index bee2c521..c317bb5f 100644
> --- a/src/mm-broadband-bearer.h
> +++ b/src/mm-broadband-bearer.h
> @@ -25,6 +25,7 @@
> #define _LIBMM_INSIDE_MM
> #include <libmm-glib.h>
>
> +#include "mm-modem-helpers.h"
> #include "mm-base-bearer.h"
> #include "mm-broadband-modem.h"
>
> @@ -39,6 +40,8 @@ typedef struct _MMBroadbandBearer
> MMBroadbandBearer;
> typedef struct _MMBroadbandBearerClass MMBroadbandBearerClass;
> typedef struct _MMBroadbandBearerPrivate MMBroadbandBearerPrivate;
>
> +#define MM_BROADBAND_BEARER_FLOW_CONTROL "broadband-bearer-flow-
> control"
> +
> struct _MMBroadbandBearer {
> MMBaseBearer parent;
> MMBroadbandBearerPrivate *priv;
> diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
> index e5ad3548..4d131fc3 100644
> --- a/src/mm-broadband-modem.c
> +++ b/src/mm-broadband-modem.c
> @@ -55,6 +55,7 @@
> #include "libqcdm/src/commands.h"
> #include "libqcdm/src/logs.h"
> #include "libqcdm/src/log-items.h"
> +#include "mm-helper-enums-types.h"
>
> static void iface_modem_init (MMIfaceModem *iface);
> static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
> @@ -115,9 +116,12 @@ enum {
> PROP_MODEM_VOICE_CALL_LIST,
> PROP_MODEM_SIMPLE_STATUS,
> PROP_MODEM_SIM_HOT_SWAP_SUPPORTED,
> + PROP_FLOW_CONTROL,
> PROP_LAST
> };
>
> +static GParamSpec *properties[PROP_LAST];
> +
> /* When CIND is supported, invalid indicators are marked with this
> value */
> #define CIND_INDICATOR_INVALID 255
> #define CIND_INDICATOR_IS_VALID(u) (u != CIND_INDICATOR_INVALID)
> @@ -146,6 +150,7 @@ struct _MMBroadbandModemPrivate {
> guint modem_cind_max_signal_quality;
> guint modem_cind_indicator_roaming;
> guint modem_cind_indicator_service;
> + MMFlowControl flow_control;
>
> /*<--- Modem 3GPP interface --->*/
> /* Properties */
> @@ -3101,17 +3106,20 @@ modem_setup_flow_control_finish
> (MMIfaceModem *self,
> }
>
> static void
> -ifc_test_ready (MMBaseModem *self,
> +ifc_test_ready (MMBaseModem *_self,
> GAsyncResult *res,
> GTask *task)
> {
> - GError *error = NULL;
> - const gchar *response;
> - MMFlowControl mask;
> - const gchar *cmd;
> + MMBroadbandModem *self;
> + GError *error = NULL;
> + const gchar *response;
> + MMFlowControl mask;
> + const gchar *cmd;
> +
> + self = MM_BROADBAND_MODEM (_self);
>
> /* Completely ignore errors in AT+IFC=? */
> - response = mm_base_modem_at_command_finish (self, res, &error);
> + response = mm_base_modem_at_command_finish (_self, res, &error);
> if (!response)
> goto out;
>
> @@ -3125,17 +3133,23 @@ ifc_test_ready (MMBaseModem *self,
> * XON/XOFF
> * None.
> */
> - if (mask & MM_FLOW_CONTROL_RTS_CTS)
> + if (mask & MM_FLOW_CONTROL_RTS_CTS) {
> + self->priv->flow_control = MM_FLOW_CONTROL_RTS_CTS;
> cmd = "+IFC=2,2";
> - else if (mask & MM_FLOW_CONTROL_XON_XOFF)
> + } else if (mask & MM_FLOW_CONTROL_XON_XOFF) {
> + self->priv->flow_control = MM_FLOW_CONTROL_XON_XOFF;
> cmd = "+IFC=1,1";
> - else if (mask & MM_FLOW_CONTROL_NONE)
> + } else if (mask & MM_FLOW_CONTROL_NONE) {
> + self->priv->flow_control = MM_FLOW_CONTROL_NONE;
> cmd = "+IFC=0,0";
> - else
> + } else
> g_assert_not_reached ();
>
> + /* Notify the flow control property update */
> + g_object_notify_by_pspec (G_OBJECT (self),
> properties[PROP_FLOW_CONTROL]);
> +
> /* Set flow control settings and ignore result */
> - mm_base_modem_at_command (self, cmd, 3, FALSE, NULL, NULL);
> + mm_base_modem_at_command (_self, cmd, 3, FALSE, NULL, NULL);
>
> out:
> /* Ignore errors */
> @@ -10623,6 +10637,9 @@ get_property (GObject *object,
> case PROP_MODEM_SIM_HOT_SWAP_SUPPORTED:
> g_value_set_boolean (value, self->priv-
> >sim_hot_swap_supported);
> break;
> + case PROP_FLOW_CONTROL:
> + g_value_set_flags (value, self->priv->flow_control);
> + break;
> default:
> G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
> break;
> @@ -10652,6 +10669,7 @@ mm_broadband_modem_init (MMBroadbandModem
> *self)
> self->priv->current_sms_mem1_storage = MM_SMS_STORAGE_UNKNOWN;
> self->priv->current_sms_mem2_storage = MM_SMS_STORAGE_UNKNOWN;
> self->priv->sim_hot_swap_supported = FALSE;
> + self->priv->flow_control = MM_FLOW_CONTROL_NONE;
> }
>
> static void
> @@ -11114,4 +11132,13 @@ mm_broadband_modem_class_init
> (MMBroadbandModemClass *klass)
> g_object_class_override_property (object_class,
> PROP_MODEM_SIM_HOT_SWAP_SUPPOR
> TED,
> MM_IFACE_MODEM_SIM_HOT_SWAP_SU
> PPORTED);
> +
> + properties[PROP_FLOW_CONTROL] =
> + g_param_spec_flags (MM_BROADBAND_MODEM_FLOW_CONTROL,
> + "Flow control",
> + "Flow control settings to use in the
> connected TTY",
> + MM_TYPE_FLOW_CONTROL,
> + MM_FLOW_CONTROL_NONE,
> + G_PARAM_READABLE);
> + g_object_class_install_property (object_class,
> PROP_FLOW_CONTROL, properties[PROP_FLOW_CONTROL]);
> }
> diff --git a/src/mm-broadband-modem.h b/src/mm-broadband-modem.h
> index d6b55d9d..4625b22a 100644
> --- a/src/mm-broadband-modem.h
> +++ b/src/mm-broadband-modem.h
> @@ -24,6 +24,7 @@
>
> #include <ModemManager.h>
>
> +#include "mm-modem-helpers.h"
> #include "mm-charsets.h"
> #include "mm-base-modem.h"
>
> @@ -38,6 +39,8 @@ typedef struct _MMBroadbandModem MMBroadbandModem;
> typedef struct _MMBroadbandModemClass MMBroadbandModemClass;
> typedef struct _MMBroadbandModemPrivate MMBroadbandModemPrivate;
>
> +#define MM_BROADBAND_MODEM_FLOW_CONTROL "broadband-modem-flow-
> control"
> +
> struct _MMBroadbandModem {
> MMBaseModem parent;
> MMBroadbandModemPrivate *priv;
> diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
> index bd10b940..297e15df 100644
> --- a/src/mm-modem-helpers.h
> +++ b/src/mm-modem-helpers.h
> @@ -101,7 +101,7 @@ GRegex *mm_voice_clip_regex_get (void);
> * For simplicity, we'll only consider flow control methods
> available in both
> * TE and TA. */
>
> -typedef enum {
> +typedef enum { /*< underscore_name=mm_flow_control >*/
> MM_FLOW_CONTROL_UNKNOWN = 0,
> MM_FLOW_CONTROL_NONE = 1 << 0, /* IFC=0,0 */
> MM_FLOW_CONTROL_XON_XOFF = 1 << 1, /* IFC=1,1 */
> --
> 2.12.2
> _______________________________________________
> ModemManager-devel mailing list
> ModemManager-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/modemmanager-devel
More information about the ModemManager-devel
mailing list