aboutsummaryrefslogtreecommitdiff
path: root/src/mm-base-modem.c
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2021-02-12 12:29:49 +0100
committerAleksander Morgado <aleksander@aleksander.es>2021-03-10 12:58:12 +0100
commit897e48709d1f5238f5165a5e5ed42937b0784c80 (patch)
tree1431a6724c6314272975c893ebc273e2f4dea845 /src/mm-base-modem.c
parent21174f289f1370c1badb10106045490604ccbdf4 (diff)
base-modem: allow grabbing link ports after modem is created
We will grab the ports and make them available through find_ports() or peek_port() or get_port(). The link ports are not 'organized' so they won't be available in e.g. get_data_ports(), which is fine, because we don't want to mix them with the real data ports exposed by the device. Link port additions and removals are also notified via signals in the modem object, so that explicit wait for specific ports can be done.
Diffstat (limited to 'src/mm-base-modem.c')
-rw-r--r--src/mm-base-modem.c182
1 files changed, 155 insertions, 27 deletions
diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c
index 79506a3a..8122a0ee 100644
--- a/src/mm-base-modem.c
+++ b/src/mm-base-modem.c
@@ -61,7 +61,14 @@ enum {
PROP_LAST
};
+enum {
+ SIGNAL_LINK_PORT_GRABBED,
+ SIGNAL_LINK_PORT_RELEASED,
+ SIGNAL_LAST
+};
+
static GParamSpec *properties[PROP_LAST];
+static guint signals[SIGNAL_LAST];
struct _MMBaseModemPrivate {
/* The connection to the system bus */
@@ -120,6 +127,10 @@ struct _MMBaseModemPrivate {
/* MBIM ports */
GList *mbim;
#endif
+
+ /* Additional port links grabbed after having
+ * organized ports */
+ GHashTable *link_ports;
};
guint
@@ -259,12 +270,13 @@ base_modem_create_virtual_port (MMBaseModem *self,
return MM_PORT (mm_port_serial_at_new (name, MM_PORT_SUBSYS_UNIX));
}
-gboolean
-mm_base_modem_grab_port (MMBaseModem *self,
- MMKernelDevice *kernel_device,
- MMPortType ptype,
- MMPortSerialAtFlag at_pflags,
- GError **error)
+static MMPort *
+base_modem_internal_grab_port (MMBaseModem *self,
+ MMKernelDevice *kernel_device,
+ gboolean link_port,
+ MMPortType ptype,
+ MMPortSerialAtFlag at_pflags,
+ GError **error)
{
MMPort *port;
const gchar *subsys;
@@ -280,7 +292,7 @@ mm_base_modem_grab_port (MMBaseModem *self,
if (port) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"Cannot add port '%s/%s', already exists", subsys, name);
- return FALSE;
+ return NULL;
}
/* Explicitly ignored ports, grab them but explicitly flag them as ignored
@@ -301,7 +313,7 @@ mm_base_modem_grab_port (MMBaseModem *self,
if (!port) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
"Cannot add port '%s/%s', unhandled port type", subsys, name);
- return FALSE;
+ return NULL;
}
/* Store kernel device */
@@ -339,11 +351,96 @@ mm_base_modem_grab_port (MMBaseModem *self,
/* Add it to the tracking HT.
* Note: 'key' and 'port' now owned by the HT. */
- mm_obj_dbg (port, "port grabbed");
- g_hash_table_insert (self->priv->ports, g_steal_pointer (&key), port);
+ if (link_port)
+ g_hash_table_insert (self->priv->link_ports, g_steal_pointer (&key), port);
+ else
+ g_hash_table_insert (self->priv->ports, g_steal_pointer (&key), port);
+ return port;
+}
+
+gboolean
+mm_base_modem_grab_port (MMBaseModem *self,
+ MMKernelDevice *kernel_device,
+ MMPortType ptype,
+ MMPortSerialAtFlag at_pflags,
+ GError **error)
+{
+ if (!base_modem_internal_grab_port (self, kernel_device, FALSE, ptype, at_pflags, error))
+ return FALSE;
+
+ mm_obj_dbg (self, "port '%s/%s' grabbed",
+ mm_kernel_device_get_subsystem (kernel_device),
+ mm_kernel_device_get_name (kernel_device));
return TRUE;
}
+/******************************************************************************/
+
+gboolean
+mm_base_modem_grab_link_port (MMBaseModem *self,
+ MMKernelDevice *kernel_device,
+ GError **error)
+{
+ const gchar *subsystem;
+ const gchar *name;
+ MMPort *port;
+
+ /* To simplify things, we only support NET link ports at this point */
+ subsystem = mm_kernel_device_get_subsystem (kernel_device);
+ name = mm_kernel_device_get_name (kernel_device);
+
+ if (!g_str_equal (subsystem, "net")) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "Cannot add port '%s/%s', unexpected link port subsystem", subsystem, name);
+ return FALSE;
+ }
+
+ /* all the newly added link ports will NOT be 'organized'; i.e. they won't
+ * be available as 'data ports' in the modem, but they can be looked up
+ * by name */
+ port = base_modem_internal_grab_port (self,
+ kernel_device,
+ TRUE,
+ MM_PORT_TYPE_NET,
+ MM_PORT_SERIAL_AT_FLAG_NONE,
+ error);
+ if (!port)
+ return FALSE;
+
+
+ mm_obj_dbg (self, "link port '%s/%s' grabbed", subsystem, name);
+ g_signal_emit (self, signals[SIGNAL_LINK_PORT_GRABBED], 0, port);
+ return TRUE;
+}
+
+gboolean
+mm_base_modem_release_link_port (MMBaseModem *self,
+ const gchar *subsystem,
+ const gchar *name,
+ GError **error)
+{
+ g_autofree gchar *key = NULL;
+ MMPort *port;
+
+ key = g_strdup_printf ("%s%s", subsystem, name);
+ port = g_hash_table_lookup (self->priv->link_ports, key);
+ if (!port) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "Cannot release link port '%s/%s', not grabbed", subsystem, name);
+ return FALSE;
+ }
+
+ /* make sure the port object is valid during the port release signal */
+ g_object_ref (port);
+ g_hash_table_remove (self->priv->link_ports, key);
+ mm_obj_dbg (self, "link port '%s/%s' released", subsystem, name);
+ g_signal_emit (self, signals[SIGNAL_LINK_PORT_RELEASED], 0, port);
+ g_object_unref (port);
+ return TRUE;
+}
+
+/******************************************************************************/
+
gboolean
mm_base_modem_disable_finish (MMBaseModem *self,
GAsyncResult *res,
@@ -851,18 +948,18 @@ mm_base_modem_find_ports (MMBaseModem *self,
return g_list_sort (out, (GCompareFunc) port_cmp);
}
-MMPort *
-mm_base_modem_peek_port (MMBaseModem *self,
- const gchar *name)
+static MMPort *
+peek_port_in_ht (GHashTable *ht,
+ const gchar *name)
{
GHashTableIter iter;
gpointer value;
gpointer key;
- if (!self->priv->ports)
+ if (!ht)
return NULL;
- g_hash_table_iter_init (&iter, self->priv->ports);
+ g_hash_table_iter_init (&iter, ht);
while (g_hash_table_iter_next (&iter, &key, &value)) {
MMPort *port = MM_PORT (value);
@@ -874,6 +971,19 @@ mm_base_modem_peek_port (MMBaseModem *self,
}
MMPort *
+mm_base_modem_peek_port (MMBaseModem *self,
+ const gchar *name)
+{
+ MMPort *found;
+
+ found = peek_port_in_ht (self->priv->ports, name);
+ if (!found)
+ found = peek_port_in_ht (self->priv->link_ports, name);
+
+ return found;
+}
+
+MMPort *
mm_base_modem_get_port (MMBaseModem *self,
const gchar *name)
{
@@ -1362,13 +1472,10 @@ base_modem_cancelled (GCancellable *cancellable,
/*****************************************************************************/
static void
-setup_ports_table (MMBaseModem *self)
+setup_ports_table (GHashTable **ht)
{
- g_assert (!self->priv->ports);
- self->priv->ports = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- g_object_unref);
+ g_assert (ht && !*ht);
+ *ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
}
static void
@@ -1406,19 +1513,20 @@ cleanup_modem_port (MMBaseModem *self,
}
static void
-teardown_ports_table (MMBaseModem *self)
+teardown_ports_table (MMBaseModem *self,
+ GHashTable **ht)
{
GHashTableIter iter;
gpointer value;
gpointer key;
- if (!self->priv->ports)
+ if (!*ht)
return;
- g_hash_table_iter_init (&iter, self->priv->ports);
+ g_hash_table_iter_init (&iter, *ht);
while (g_hash_table_iter_next (&iter, &key, &value))
cleanup_modem_port (self, MM_PORT (value));
- g_hash_table_destroy (g_steal_pointer (&self->priv->ports));
+ g_hash_table_destroy (g_steal_pointer (ht));
}
/*****************************************************************************/
@@ -1461,7 +1569,8 @@ mm_base_modem_init (MMBaseModem *self)
self->priv->max_timeouts = DEFAULT_MAX_TIMEOUTS;
- setup_ports_table (self);
+ setup_ports_table (&self->priv->ports);
+ setup_ports_table (&self->priv->link_ports);
}
static void
@@ -1618,7 +1727,8 @@ dispose (GObject *object)
g_list_free_full (g_steal_pointer (&self->priv->mbim), g_object_unref);
#endif
- teardown_ports_table (self);
+ teardown_ports_table (self, &self->priv->link_ports);
+ teardown_ports_table (self, &self->priv->ports);
g_clear_object (&self->priv->connection);
@@ -1732,4 +1842,22 @@ mm_base_modem_class_init (MMBaseModemClass *klass)
FALSE,
G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_DATA_TTY_SUPPORTED, properties[PROP_DATA_TTY_SUPPORTED]);
+
+ signals[SIGNAL_LINK_PORT_GRABBED] =
+ g_signal_new (MM_BASE_MODEM_SIGNAL_LINK_PORT_GRABBED,
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (MMBaseModemClass, link_port_grabbed),
+ NULL, NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE, 1, MM_TYPE_PORT);
+
+ signals[SIGNAL_LINK_PORT_RELEASED] =
+ g_signal_new (MM_BASE_MODEM_SIGNAL_LINK_PORT_RELEASED,
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (MMBaseModemClass, link_port_released),
+ NULL, NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE, 1, MM_TYPE_PORT);
}