aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mm-base-modem.c182
-rw-r--r--src/mm-base-modem.h26
-rw-r--r--src/mm-device.c25
3 files changed, 200 insertions, 33 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);
}
diff --git a/src/mm-base-modem.h b/src/mm-base-modem.h
index 2fd534e1..19fa8eb9 100644
--- a/src/mm-base-modem.h
+++ b/src/mm-base-modem.h
@@ -67,6 +67,9 @@ typedef struct _MMBaseModemPrivate MMBaseModemPrivate;
#define MM_BASE_MODEM_DATA_NET_SUPPORTED "base-modem-data-net-supported"
#define MM_BASE_MODEM_DATA_TTY_SUPPORTED "base-modem-data-tty-supported"
+#define MM_BASE_MODEM_SIGNAL_LINK_PORT_GRABBED "base-modem-link-port-grabbed"
+#define MM_BASE_MODEM_SIGNAL_LINK_PORT_RELEASED "base-modem-link-port-released"
+
struct _MMBaseModem {
MmGdbusObjectSkeleton parent;
MMBaseModemPrivate *priv;
@@ -104,6 +107,12 @@ struct _MMBaseModemClass {
gboolean (*disable_finish) (MMBaseModem *self,
GAsyncResult *res,
GError **error);
+
+ /* signals */
+ void (* link_port_grabbed) (MMBaseModem *self,
+ MMPort *link_port);
+ void (* link_port_released) (MMBaseModem *self,
+ MMPort *link_port);
};
GType mm_base_modem_get_type (void);
@@ -111,11 +120,18 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMBaseModem, g_object_unref)
guint mm_base_modem_get_dbus_id (MMBaseModem *self);
-gboolean mm_base_modem_grab_port (MMBaseModem *self,
- MMKernelDevice *kernel_device,
- MMPortType ptype,
- MMPortSerialAtFlag at_pflags,
- GError **error);
+gboolean mm_base_modem_grab_port (MMBaseModem *self,
+ MMKernelDevice *kernel_device,
+ MMPortType ptype,
+ MMPortSerialAtFlag at_pflags,
+ GError **error);
+gboolean mm_base_modem_grab_link_port (MMBaseModem *self,
+ MMKernelDevice *kernel_device,
+ GError **error);
+gboolean mm_base_modem_release_link_port (MMBaseModem *self,
+ const gchar *subsystem,
+ const gchar *name,
+ GError **error);
gboolean mm_base_modem_has_at_port (MMBaseModem *self);
diff --git a/src/mm-device.c b/src/mm-device.c
index d0e31184..cfeb450b 100644
--- a/src/mm-device.c
+++ b/src/mm-device.c
@@ -211,11 +211,28 @@ void
mm_device_grab_port (MMDevice *self,
MMKernelDevice *kernel_port)
{
- MMPortProbe *probe;
+ MMPortProbe *probe;
+ MMKernelDevice *lower_port;
if (mm_device_owns_port (self, kernel_port))
return;
+ lower_port = mm_kernel_device_peek_lower_device (kernel_port);
+ if (lower_port) {
+ g_autoptr(GError) error = NULL;
+
+ /* No port probing done, at this point this is not something we require
+ * as all the virtual instantiated ports are net devices. We also avoid
+ * emitting the PORT_GRABBED signal in the MMDevice, because that is
+ * exclusively linked to a port being added to the list of probes, which
+ * we don't do here. */
+ if (self->priv->modem && !mm_base_modem_grab_link_port (self->priv->modem, kernel_port, &error))
+ mm_obj_dbg (self, "fully ignoring link port %s from now on: %s",
+ mm_kernel_device_get_name (kernel_port),
+ error->message);
+ return;
+ }
+
/* Get the vendor/product IDs out of the first one that gives us
* some valid value (it seems we may get NULL reported for VID in QMI
* ports, e.g. Huawei E367) */
@@ -242,6 +259,12 @@ mm_device_release_port_name (MMDevice *self,
{
MMPortProbe *probe;
+ /* If modem exists, try to remove it as a link port. We also avoid emitting
+ * the PORT_RELEASED signal in this case, as the link ports are not associated
+ * to the port probe list */
+ if (self->priv->modem && mm_base_modem_release_link_port (self->priv->modem, subsystem, name, NULL))
+ return;
+
probe = device_find_probe_with_name (self, subsystem, name);
if (probe) {
/* Found, remove from lists and destroy probe */