api,introspection: new 'Ports' property in the Modem interface

We will expose a new 'Ports' property listing all ports currently known by a
given modem. Ports which are not used but are detected as being part of the
modem will be listed with an 'unknown' port type.

This change uses the new 'MMModemPortType' enum and the new 'MMModemPortInfo'
helper struct to handle these values in libmm-glib. The already available
'MMPortType' enum hasn't been re-used for the interface because it contains
values that we don't need (e.g. IGNORED).

The port list is now also included in the modem information command of mmcli:

$ sudo mmcli -m 0

/org/freedesktop/ModemManager1/Modem/0 (device id '97b7b99e3e2bea103880545b619fb05a3cc81b26')
  -------------------------
  System   |         device: '/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4'
           |        drivers: 'qcserial, qmi_wwan'
           |         plugin: 'Gobi'
           |   primary port: 'cdc-wdm0'
           |          ports: 'ttyUSB0 (qcdm), ttyUSB1 (at), cdc-wdm0 (qmi), wwp0s29u1u4 (net)'

https://bugzilla.gnome.org/show_bug.cgi?id=702678
This commit is contained in:
Aleksander Morgado
2013-06-20 23:45:12 +02:00
parent 30fe6eab48
commit 3206e95663
15 changed files with 407 additions and 2 deletions

View File

@@ -260,6 +260,9 @@ print_modem_info (void)
gchar *own_numbers_string;
MMModemBand *bands = NULL;
guint n_bands = 0;
MMModemPortInfo *ports = NULL;
guint n_ports = 0;
gchar *ports_string;
MMUnlockRetries *unlock_retries;
guint signal_quality = 0;
gboolean signal_quality_recent = FALSE;
@@ -288,6 +291,9 @@ print_modem_info (void)
mm_modem_get_supported_bands (ctx->modem, &bands, &n_bands);
supported_bands_string = mm_common_build_bands_string (bands, n_bands);
g_free (bands);
mm_modem_get_ports (ctx->modem, &ports, &n_ports);
ports_string = mm_common_build_ports_string (ports, n_ports);
mm_modem_port_info_array_free (ports, n_ports);
if (mm_modem_get_current_modes (ctx->modem, &allowed_modes, &preferred_mode)) {
allowed_modes_string = mm_modem_mode_build_string_from_mask (allowed_modes);
preferred_mode_string = mm_modem_mode_build_string_from_mask (preferred_mode);
@@ -371,11 +377,13 @@ print_modem_info (void)
" System | device: '%s'\n"
" | drivers: '%s'\n"
" | plugin: '%s'\n"
" | primary port: '%s'\n",
" | primary port: '%s'\n"
" | ports: '%s'\n",
VALIDATE_UNKNOWN (mm_modem_get_device (ctx->modem)),
VALIDATE_UNKNOWN (drivers_string),
VALIDATE_UNKNOWN (mm_modem_get_plugin (ctx->modem)),
VALIDATE_UNKNOWN (mm_modem_get_primary_port (ctx->modem)));
VALIDATE_UNKNOWN (mm_modem_get_primary_port (ctx->modem)),
VALIDATE_UNKNOWN (ports_string));
/* Numbers related stuff */
g_print (" -------------------------\n"
@@ -489,6 +497,7 @@ print_modem_info (void)
VALIDATE_PATH (mm_modem_get_sim_path (ctx->modem)));
g_print ("\n");
g_free (ports_string);
g_free (supported_ip_families_string);
g_free (current_bands_string);
g_free (supported_bands_string);

View File

@@ -32,6 +32,7 @@ MMModemState
MMModemStateFailedReason
MMModemStateChangeReason
MMModemPowerState
MMModemPortType
MMSmsPduType
MMSmsState
MMSmsDeliveryState

View File

@@ -74,6 +74,7 @@ mm_object_get_type
<TITLE>MMModem</TITLE>
MMModem
MMModemModeCombination
MMModemPortInfo
<SUBSECTION Getters>
mm_modem_get_path
mm_modem_dup_path
@@ -95,6 +96,8 @@ mm_modem_get_plugin
mm_modem_dup_plugin
mm_modem_get_primary_port
mm_modem_dup_primary_port
mm_modem_peek_ports
mm_modem_get_ports
mm_modem_get_device
mm_modem_dup_device
mm_modem_get_equipment_identifier
@@ -162,6 +165,8 @@ mm_modem_delete_bearer_sync
mm_modem_command
mm_modem_command_finish
mm_modem_command_sync
<SUBSECTION Other>
mm_modem_port_info_array_free
<SUBSECTION Standard>
MMModemClass
MMModemPrivate
@@ -970,6 +975,7 @@ mm_modem_lock_get_string
mm_modem_access_technology_build_string_from_mask
mm_modem_mode_build_string_from_mask
mm_modem_band_get_string
mm_modem_port_type_get_string
mm_modem_3gpp_registration_state_get_string
mm_modem_3gpp_facility_build_string_from_mask
mm_modem_3gpp_network_availability_get_string
@@ -1013,6 +1019,7 @@ mm_modem_3gpp_facility_get_string
mm_modem_3gpp_network_availability_build_string_from_mask
mm_modem_3gpp_ussd_session_state_build_string_from_mask
mm_firmware_image_type_build_string_from_mask
mm_modem_port_type_build_string_from_mask
<SUBSECTION Standard>
MM_TYPE_BEARER_IP_FAMILY
MM_TYPE_BEARER_IP_METHOD
@@ -1036,6 +1043,7 @@ MM_TYPE_MODEM_STATE
MM_TYPE_MODEM_STATE_FAILED_REASON
MM_TYPE_MODEM_STATE_CHANGE_REASON
MM_TYPE_MODEM_POWER_STATE
MM_TYPE_MODEM_PORT_TYPE
MM_TYPE_SMS_DELIVERY_STATE
MM_TYPE_SMS_PDU_TYPE
MM_TYPE_SMS_STATE
@@ -1063,6 +1071,7 @@ mm_modem_state_change_reason_get_type
mm_modem_state_get_type
mm_modem_state_failed_reason_get_type
mm_modem_power_state_get_type
mm_modem_port_type_get_type
mm_sms_delivery_state_get_type
mm_sms_pdu_type_get_type
mm_sms_state_get_type
@@ -1443,6 +1452,8 @@ mm_gdbus_modem_dup_plugin
mm_gdbus_modem_get_power_state
mm_gdbus_modem_get_primary_port
mm_gdbus_modem_dup_primary_port
mm_gdbus_modem_get_ports
mm_gdbus_modem_dup_ports
mm_gdbus_modem_get_revision
mm_gdbus_modem_dup_revision
mm_gdbus_modem_get_signal_quality
@@ -1511,6 +1522,7 @@ mm_gdbus_modem_set_model
mm_gdbus_modem_set_own_numbers
mm_gdbus_modem_set_plugin
mm_gdbus_modem_set_primary_port
mm_gdbus_modem_set_ports
mm_gdbus_modem_set_revision
mm_gdbus_modem_set_signal_quality
mm_gdbus_modem_set_sim

View File

@@ -394,6 +394,28 @@ typedef enum { /*< underscore_name=mm_modem_band >*/
MM_MODEM_BAND_ANY = 256
} MMModemBand;
/**
* MMModemPortType:
* @MM_MODEM_PORT_TYPE_UNKNOWN: Unknown.
* @MM_MODEM_PORT_TYPE_NET: Net port.
* @MM_MODEM_PORT_TYPE_AT: AT port.
* @MM_MODEM_PORT_TYPE_QCDM: QCDM port.
* @MM_MODEM_PORT_TYPE_GPS: GPS port.
* @MM_MODEM_PORT_TYPE_QMI: QMI port.
* @MM_MODEM_PORT_TYPE_MBIM: MBIM port.
*
* Type of modem port.
*/
typedef enum { /*< underscore_name=mm_modem_port_type >*/
MM_MODEM_PORT_TYPE_UNKNOWN = 1,
MM_MODEM_PORT_TYPE_NET = 2,
MM_MODEM_PORT_TYPE_AT = 3,
MM_MODEM_PORT_TYPE_QCDM = 4,
MM_MODEM_PORT_TYPE_GPS = 5,
MM_MODEM_PORT_TYPE_QMI = 6,
MM_MODEM_PORT_TYPE_MBIM = 7
} MMModemPortType;
/**
* MMSmsPduType:
* @MM_SMS_PDU_TYPE_UNKNOWN: Unknown type.

View File

@@ -326,6 +326,16 @@
-->
<property name="PrimaryPort" type="s" access="read" />
<!--
Ports:
The list of ports in the modem, given as an array of string and unsigned
integer pairs. The string is the port name or path, and the integer is
the port type given as a
<link linkend="MMModemPortType">MMModemPortType</link> value.
-->
<property name="Ports" type="a(su)" access="read" />
<!--
EquipmentIdentifier:

View File

@@ -6,6 +6,7 @@ libmm_glib_la_SOURCES = \
libmm-glib.h \
mm-helpers.h \
mm-helper-types.h \
mm-helper-types.c \
mm-manager.h \
mm-manager.c \
mm-object.h \

View File

@@ -77,6 +77,31 @@ mm_common_build_bands_string (const MMModemBand *bands,
return g_string_free (str, FALSE);
}
gchar *
mm_common_build_ports_string (const MMModemPortInfo *ports,
guint n_ports)
{
gboolean first = TRUE;
GString *str;
guint i;
if (!ports || !n_ports)
return g_strdup ("none");
str = g_string_new ("");
for (i = 0; i < n_ports; i++) {
g_string_append_printf (str, "%s%s (%s)",
first ? "" : ", ",
ports[i].name,
mm_modem_port_type_get_string (ports[i].type));
if (first)
first = FALSE;
}
return g_string_free (str, FALSE);
}
gchar *
mm_common_build_sms_storages_string (const MMSmsStorage *storages,
guint n_storages)
@@ -194,6 +219,72 @@ mm_common_sms_storages_garray_to_variant (GArray *array)
return mm_common_sms_storages_array_to_variant (NULL, 0);
}
GArray *
mm_common_ports_variant_to_garray (GVariant *variant)
{
GArray *array = NULL;
if (variant) {
guint i;
guint n;
n = g_variant_n_children (variant);
if (n > 0) {
array = g_array_sized_new (FALSE, FALSE, sizeof (MMModemPortInfo), n);
for (i = 0; i < n; i++) {
MMModemPortInfo info;
g_variant_get_child (variant, i, "(su)", &info.name, &info.type);
g_array_append_val (array, info);
}
}
}
return array;
}
MMModemPortInfo *
mm_common_ports_variant_to_array (GVariant *variant,
guint *n_ports)
{
GArray *array;
array = mm_common_ports_variant_to_garray (variant);
if (n_ports)
*n_ports = array->len;
return (MMModemPortInfo *) g_array_free (array, FALSE);
}
GVariant *
mm_common_ports_array_to_variant (const MMModemPortInfo *ports,
guint n_ports)
{
GVariantBuilder builder;
guint i;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(su)"));
for (i = 0; i < n_ports; i++) {
GVariant *tuple[2];
tuple[0] = g_variant_new_string (ports[i].name);
tuple[1] = g_variant_new_uint32 ((guint32)ports[i].type);
g_variant_builder_add_value (&builder, g_variant_new_tuple (tuple, 2));
}
return g_variant_builder_end (&builder);
}
GVariant *
mm_common_ports_garray_to_variant (GArray *array)
{
if (array)
return mm_common_ports_array_to_variant ((const MMModemPortInfo *)array->data,
array->len);
return mm_common_ports_array_to_variant (NULL, 0);
}
MMModemCapability
mm_common_get_capabilities_from_string (const gchar *str,
GError **error)

View File

@@ -32,6 +32,9 @@ gchar *mm_common_build_capabilities_string (const MMModemCapability *capabilitie
gchar *mm_common_build_bands_string (const MMModemBand *bands,
guint n_bands);
gchar *mm_common_build_ports_string (const MMModemPortInfo *ports,
guint n_ports);
gchar *mm_common_build_sms_storages_string (const MMSmsStorage *storages,
guint n_storages);
@@ -57,6 +60,13 @@ MMBearerAllowedAuth mm_common_get_allowed_auth_from_string (const gchar *str,
MMSmsStorage mm_common_get_sms_storage_from_string (const gchar *str,
GError **error);
GArray *mm_common_ports_variant_to_garray (GVariant *variant);
MMModemPortInfo *mm_common_ports_variant_to_array (GVariant *variant,
guint *n_ports);
GVariant *mm_common_ports_array_to_variant (const MMModemPortInfo *ports,
guint n_ports);
GVariant *mm_common_ports_garray_to_variant (GArray *array);
GArray *mm_common_sms_storages_variant_to_garray (GVariant *variant);
MMSmsStorage *mm_common_sms_storages_variant_to_array (GVariant *variant,
guint *n_storages);

View File

@@ -0,0 +1,41 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* libmm -- Access modem status & information from glib applications
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
*/
#include "mm-helper-types.h"
/**
* mm_modem_port_info_array_free:
* @array: an array of #MMModemPortInfo values.
* @array_size: length of @array.
*
* Frees an array of #MMModemPortInfo values.
*/
void
mm_modem_port_info_array_free (MMModemPortInfo *array,
guint array_size)
{
guint i;
for (i = 0; i < array_size; i++)
g_free (array[i].name);
g_free (array);
}

View File

@@ -21,6 +21,7 @@
*/
#include <ModemManager.h>
#include <glib.h>
#if !defined (__LIBMM_GLIB_H_INSIDE__) && !defined (LIBMM_GLIB_COMPILATION)
#error "Only <libmm-glib.h> can be included directly."
@@ -41,4 +42,19 @@ typedef struct _MMModemModeCombination {
MMModemMode preferred;
} MMModemModeCombination;
/**
* MMModemPortInfo:
* @name: Name of the port.
* @type: A #MMModemPortType value.
*
* Information of a given port.
*/
typedef struct _MMModemPortInfo {
gchar *name;
MMModemPortType type;
} MMModemPortInfo;
void mm_modem_port_info_array_free (MMModemPortInfo *array,
guint array_size);
#endif /* _MM_HELPER_TYPES_H_ */

View File

@@ -44,6 +44,11 @@
G_DEFINE_TYPE (MMModem, mm_modem, MM_GDBUS_TYPE_MODEM_PROXY)
struct _MMModemPrivate {
/* Ports */
GMutex ports_mutex;
guint ports_id;
GArray *ports;
/* UnlockRetries */
GMutex unlock_retries_mutex;
guint unlock_retries_id;
@@ -683,6 +688,124 @@ mm_modem_dup_primary_port (MMModem *self)
/*****************************************************************************/
static void
ports_updated (MMModem *self,
GParamSpec *pspec)
{
g_mutex_lock (&self->priv->ports_mutex);
{
GVariant *dictionary;
if (self->priv->ports)
g_array_unref (self->priv->ports);
dictionary = mm_gdbus_modem_get_ports (MM_GDBUS_MODEM (self));
self->priv->ports = (dictionary ?
mm_common_ports_variant_to_garray (dictionary) :
NULL);
}
g_mutex_unlock (&self->priv->ports_mutex);
}
static gboolean
ensure_internal_ports (MMModem *self,
MMModemPortInfo **dup_ports,
guint *dup_ports_n)
{
gboolean ret;
g_mutex_lock (&self->priv->ports_mutex);
{
/* If this is the first time ever asking for the array, setup the
* update listener and the initial array, if any. */
if (!self->priv->ports_id) {
GVariant *dictionary;
dictionary = mm_gdbus_modem_dup_ports (MM_GDBUS_MODEM (self));
if (dictionary) {
self->priv->ports = mm_common_ports_variant_to_garray (dictionary);
g_variant_unref (dictionary);
}
/* No need to clear this signal connection when freeing self */
self->priv->ports_id =
g_signal_connect (self,
"notify::ports",
G_CALLBACK (ports_updated),
NULL);
}
if (!self->priv->ports)
ret = FALSE;
else {
ret = TRUE;
if (dup_ports && dup_ports_n) {
*dup_ports_n = self->priv->ports->len;
if (self->priv->ports->len > 0) {
*dup_ports = g_malloc (sizeof (MMModemPortInfo) * self->priv->ports->len);
memcpy (*dup_ports, self->priv->ports->data, sizeof (MMModemPortInfo) * self->priv->ports->len);
} else
*dup_ports = NULL;
}
}
}
g_mutex_unlock (&self->priv->ports_mutex);
return ret;
}
/**
* mm_modem_peek_current_ports:
* @self: A #MMModem.
* @ports: (out) (array length=n_ports): Return location for the array of #MMModemPortInfo values. Do not free the returned value, it is owned by @self.
* @n_ports: (out): Return location for the number of values in @ports.
*
* Gets the list of ports in the modem.
*
* Returns: %TRUE if @ports and @n_ports are set, %FALSE otherwise.
*/
gboolean
mm_modem_peek_ports (MMModem *self,
const MMModemPortInfo **ports,
guint *n_ports)
{
g_return_val_if_fail (MM_IS_MODEM (self), FALSE);
g_return_val_if_fail (ports != NULL, FALSE);
g_return_val_if_fail (n_ports != NULL, FALSE);
if (!ensure_internal_ports (self, NULL, NULL))
return FALSE;
*n_ports = self->priv->ports->len;
*ports = (MMModemPortInfo *)self->priv->ports->data;
return TRUE;
}
/**
* mm_modem_get_ports:
* @self: A #MMModem.
* @ports: (out) (array length=n_ports): Return location for the array of #MMModemPortInfo values. The returned array should be freed with mm_modem_port_info_array_free() when no longer needed.
* @n_ports: (out): Return location for the number of values in @ports.
*
* Gets the list of ports in the modem.
*
* Returns: %TRUE if @ports and @n_ports are set, %FALSE otherwise.
*/
gboolean
mm_modem_get_ports (MMModem *self,
MMModemPortInfo **ports,
guint *n_ports)
{
g_return_val_if_fail (MM_IS_MODEM (self), FALSE);
g_return_val_if_fail (ports != NULL, FALSE);
g_return_val_if_fail (n_ports != NULL, FALSE);
return ensure_internal_ports (self, ports, n_ports);
}
/*****************************************************************************/
/**
* mm_modem_get_equipment_identifier:
* @self: A #MMModem.

View File

@@ -111,6 +111,13 @@ gchar *mm_modem_dup_plugin (MMModem *self);
const gchar *mm_modem_get_primary_port (MMModem *self);
gchar *mm_modem_dup_primary_port (MMModem *self);
gboolean mm_modem_peek_ports (MMModem *self,
const MMModemPortInfo **ports,
guint *n_ports);
gboolean mm_modem_get_ports (MMModem *self,
MMModemPortInfo **ports,
guint *n_ports);
const gchar *mm_modem_get_equipment_identifier (MMModem *self);
gchar *mm_modem_dup_equipment_identifier (MMModem *self);

View File

@@ -968,6 +968,53 @@ mm_base_modem_has_at_port (MMBaseModem *self)
return FALSE;
}
MMModemPortInfo *
mm_base_modem_get_port_infos (MMBaseModem *self,
guint *n_port_infos)
{
GHashTableIter iter;
MMModemPortInfo *port_infos;
MMPort *port;
guint i;
*n_port_infos = g_hash_table_size (self->priv->ports);
port_infos = g_new (MMModemPortInfo, *n_port_infos);
g_hash_table_iter_init (&iter, self->priv->ports);
i = 0;
while (g_hash_table_iter_next (&iter, NULL, (gpointer)&port)) {
port_infos[i].name = g_strdup (mm_port_get_device (port));
switch (mm_port_get_port_type (port)) {
case MM_PORT_TYPE_NET:
port_infos[i].type = MM_MODEM_PORT_TYPE_NET;
break;
case MM_PORT_TYPE_AT:
port_infos[i].type = MM_MODEM_PORT_TYPE_AT;
break;
case MM_PORT_TYPE_QCDM:
port_infos[i].type = MM_MODEM_PORT_TYPE_QCDM;
break;
case MM_PORT_TYPE_GPS:
port_infos[i].type = MM_MODEM_PORT_TYPE_GPS;
break;
case MM_PORT_TYPE_QMI:
port_infos[i].type = MM_MODEM_PORT_TYPE_QMI;
break;
case MM_PORT_TYPE_MBIM:
port_infos[i].type = MM_MODEM_PORT_TYPE_MBIM;
break;
case MM_PORT_TYPE_UNKNOWN:
case MM_PORT_TYPE_IGNORED:
default:
port_infos[i].type = MM_MODEM_PORT_TYPE_UNKNOWN;
break;
}
i++;
}
return port_infos;
}
static void
initialize_ready (MMBaseModem *self,
GAsyncResult *res)

View File

@@ -23,6 +23,9 @@
#include <glib.h>
#include <glib-object.h>
#define _LIBMM_INSIDE_MM
#include <libmm-glib.h>
#include <mm-gdbus-modem.h>
#include "mm-auth.h"
@@ -155,6 +158,9 @@ MMAtSerialPort *mm_base_modem_get_best_at_port (MMBaseModem *self, GError
MMPort *mm_base_modem_get_best_data_port (MMBaseModem *self, MMPortType type);
GList *mm_base_modem_get_data_ports (MMBaseModem *self);
MMModemPortInfo *mm_base_modem_get_port_infos (MMBaseModem *self,
guint *n_port_infos);
void mm_base_modem_set_hotplugged (MMBaseModem *self,
gboolean hotplugged);
gboolean mm_base_modem_get_hotplugged (MMBaseModem *self);

View File

@@ -4019,6 +4019,15 @@ interface_initialization_step (InitializationContext *ctx)
g_assert (primary != NULL);
mm_gdbus_modem_set_primary_port (ctx->skeleton, mm_port_get_device (primary));
}
/* Load ports if not done before */
if (!mm_gdbus_modem_get_ports (ctx->skeleton)) {
MMModemPortInfo *port_infos;
guint n_port_infos;
port_infos = mm_base_modem_get_port_infos (MM_BASE_MODEM (ctx->self), &n_port_infos);
mm_gdbus_modem_set_ports (ctx->skeleton, mm_common_ports_array_to_variant (port_infos, n_port_infos));
mm_modem_port_info_array_free (port_infos, n_port_infos);
}
/* Fall down to next step */
ctx->step++;