diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2021-02-12 12:29:49 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2021-03-10 12:58:12 +0100 |
commit | 897e48709d1f5238f5165a5e5ed42937b0784c80 (patch) | |
tree | 1431a6724c6314272975c893ebc273e2f4dea845 | |
parent | 21174f289f1370c1badb10106045490604ccbdf4 (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.
-rw-r--r-- | src/mm-base-modem.c | 182 | ||||
-rw-r--r-- | src/mm-base-modem.h | 26 | ||||
-rw-r--r-- | src/mm-device.c | 25 |
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 */ |