diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/fibocom/mm-broadband-modem-mbim-fibocom.c | 3 | ||||
-rw-r--r-- | src/plugins/fibocom/mm-broadband-modem-mbim-xmm-fibocom.c | 3 | ||||
-rw-r--r-- | src/plugins/fibocom/mm-port-mbim-fibocom.c | 278 | ||||
-rw-r--r-- | src/plugins/fibocom/mm-port-mbim-fibocom.h | 59 | ||||
-rw-r--r-- | src/plugins/fibocom/mm-shared-fibocom.c | 35 | ||||
-rw-r--r-- | src/plugins/fibocom/mm-shared-fibocom.h | 7 | ||||
-rw-r--r-- | src/plugins/meson.build | 1 | ||||
-rw-r--r-- | src/plugins/mtk/mm-broadband-modem-mbim-mtk-fibocom.c | 3 |
8 files changed, 389 insertions, 0 deletions
diff --git a/src/plugins/fibocom/mm-broadband-modem-mbim-fibocom.c b/src/plugins/fibocom/mm-broadband-modem-mbim-fibocom.c index df66da3d..189af6cc 100644 --- a/src/plugins/fibocom/mm-broadband-modem-mbim-fibocom.c +++ b/src/plugins/fibocom/mm-broadband-modem-mbim-fibocom.c @@ -107,7 +107,10 @@ shared_fibocom_init (MMSharedFibocom *iface) static void mm_broadband_modem_mbim_fibocom_class_init (MMBroadbandModemMbimFibocomClass *klass) { + MMBaseModemClass *base_modem_class = MM_BASE_MODEM_CLASS (klass); MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass); + base_modem_class->create_usbmisc_port = mm_shared_fibocom_create_usbmisc_port; + base_modem_class->create_wwan_port = mm_shared_fibocom_create_wwan_port; broadband_modem_class->setup_ports = mm_shared_fibocom_setup_ports; } diff --git a/src/plugins/fibocom/mm-broadband-modem-mbim-xmm-fibocom.c b/src/plugins/fibocom/mm-broadband-modem-mbim-xmm-fibocom.c index 239247a2..86afdfdf 100644 --- a/src/plugins/fibocom/mm-broadband-modem-mbim-xmm-fibocom.c +++ b/src/plugins/fibocom/mm-broadband-modem-mbim-xmm-fibocom.c @@ -110,7 +110,10 @@ shared_fibocom_init (MMSharedFibocom *iface) static void mm_broadband_modem_mbim_xmm_fibocom_class_init (MMBroadbandModemMbimXmmFibocomClass *klass) { + MMBaseModemClass *base_modem_class = MM_BASE_MODEM_CLASS (klass); MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass); + base_modem_class->create_usbmisc_port = mm_shared_fibocom_create_usbmisc_port; + base_modem_class->create_wwan_port = mm_shared_fibocom_create_wwan_port; broadband_modem_class->setup_ports = mm_shared_fibocom_setup_ports; } diff --git a/src/plugins/fibocom/mm-port-mbim-fibocom.c b/src/plugins/fibocom/mm-port-mbim-fibocom.c new file mode 100644 index 00000000..e7d26ed0 --- /dev/null +++ b/src/plugins/fibocom/mm-port-mbim-fibocom.c @@ -0,0 +1,278 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details: + * + * Copyright (C) 2024 Google, Inc. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <ModemManager.h> +#include <mm-errors-types.h> + +#include "mm-serial-parsers.h" +#include "mm-iface-port-at.h" +#include "mm-port-mbim-fibocom.h" +#include "mm-log-object.h" + +static void iface_port_at_init (MMIfacePortAt *iface); + +G_DEFINE_TYPE_EXTENDED (MMPortMbimFibocom, mm_port_mbim_fibocom, MM_TYPE_PORT_MBIM, 0, + G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_PORT_AT, iface_port_at_init)) + +typedef enum { + FEATURE_SUPPORT_UNKNOWN, + FEATURE_NOT_SUPPORTED, + FEATURE_SUPPORTED +} FeatureSupport; + +struct _MMPortMbimFibocomPrivate { + FeatureSupport at_over_mbim; + gpointer parser; +}; + +/*****************************************************************************/ + +static gboolean +iface_port_at_check_support (MMIfacePortAt *_self, + gboolean *out_supported, + GError **error) +{ + MMPortMbimFibocom *self = MM_PORT_MBIM_FIBOCOM (_self); + + g_assert (out_supported); + + if (self->priv->at_over_mbim == FEATURE_SUPPORT_UNKNOWN) { + /* First time check */ + if (!mm_port_mbim_is_open (MM_PORT_MBIM (self))) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE, + "Couldn't check AT support: MBIM port is closed"); + return FALSE; + } + + if (!mm_port_mbim_supports_command (MM_PORT_MBIM (self), MBIM_SERVICE_FIBOCOM, MBIM_CID_FIBOCOM_AT_COMMAND)) { + mm_obj_msg (self, "MBIM device is not AT capable"); + self->priv->at_over_mbim = FEATURE_NOT_SUPPORTED; + } else { + mm_obj_msg (self, "MBIM device is AT capable"); + self->priv->at_over_mbim = FEATURE_SUPPORTED; + } + } + + *out_supported = (self->priv->at_over_mbim == FEATURE_SUPPORTED); + return TRUE; +} + +/*****************************************************************************/ +/* AT command */ + +static gchar * +iface_port_at_command_finish (MMIfacePortAt *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (res), error); +} + +static void +debug_log (MMPortMbimFibocom *self, + const gchar *prefix, + const guint8 *buf, + gsize len) +{ + g_autoptr(GString) debug = NULL; + const guint8 *s; + + debug = g_string_new (prefix); + g_string_append (debug, " '"); + + s = buf; + while (len--) { + if (g_ascii_isprint ((gchar)*s)) + g_string_append_c (debug, (gchar)*s); + else if (*s == '\r') + g_string_append (debug, "<CR>"); + else if (*s == '\n') + g_string_append (debug, "<LF>"); + else + g_string_append_printf (debug, "\\%u", (guint8) (*s & 0xFF)); + s++; + } + + g_string_append_c (debug, '\''); + mm_obj_dbg (self, "%s", debug->str); +} + +static void +at_command_ready (MbimDevice *device, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(GError) error = NULL; + MMPortMbimFibocom *self; + guint32 ret_size = 0; + const guint8 *ret_str = NULL; + g_autoptr(MbimMessage) response = NULL; + GString *string; + + self = g_task_get_source_object (task); + + response = mbim_device_command_finish (device, res, &error); + if (!response || + !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error) || + !mbim_message_fibocom_at_command_response_parse ( + response, + &ret_size, + &ret_str, + &error)) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + debug_log (self, "<--", ret_str, ret_size); + + if (G_UNLIKELY (!self->priv->parser)) + self->priv->parser = mm_serial_parser_v1_new (); + + /* Prepare the GString to pass to the parser. We add an explicit leading CRLF + * sequence only because it is what the parser expects, so that we don't need + * to do major changes to handle that case. */ + string = g_string_sized_new (ret_size + 3); + g_string_append (string, "\r\n"); + g_string_append_len (string, (const gchar *) ret_str, ret_size); + + if (!mm_serial_parser_v1_parse (self->priv->parser, string, self, &error)) { + if (error) + g_task_return_error (task, error); + else + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Incomplete response"); + g_string_free (string, TRUE); + g_object_unref (task); + return; + } + + g_task_return_pointer (task, g_string_free (string, FALSE), g_free); + g_object_unref (task); +} + +static GByteArray * +at_command_to_byte_array (const gchar *command, + gboolean is_raw) +{ + GByteArray *buf; + int cmdlen; + + cmdlen = strlen (command); + buf = g_byte_array_sized_new (cmdlen + 4); + + if (!is_raw) { + /* Make sure there's an AT in the front */ + if (!g_str_has_prefix (command, "AT")) + g_byte_array_append (buf, (const guint8 *) "AT", 2); + } + + g_byte_array_append (buf, (const guint8 *) command, cmdlen); + + if (!is_raw) { + /* Make sure there's a trailing carriage return */ + if ((cmdlen == 0) || + (command[cmdlen - 1] != '\r' && (cmdlen == 1 || command[cmdlen - 2] != '\r'))) + g_byte_array_append (buf, (const guint8 *) "\r", 1); + /* Make sure there's a trailing line-feed */ + if ((cmdlen == 0) || + (command[cmdlen - 1] != '\n' && (cmdlen == 1 || command[cmdlen - 2] != '\n'))) + g_byte_array_append (buf, (const guint8 *) "\n", 1); + } + + return buf; +} + +static void +iface_port_at_command (MMIfacePortAt *self, + const gchar *command, + guint32 timeout_seconds, + gboolean is_raw, + gboolean allow_cached, /* ignored */ + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(MbimMessage) request = NULL; + g_autoptr(GByteArray) buffer = NULL; + GTask *task; + + task = g_task_new (self, cancellable, callback, user_data); + + buffer = at_command_to_byte_array (command, is_raw); + + debug_log (MM_PORT_MBIM_FIBOCOM (self), "-->", buffer->data, buffer->len); + + request = mbim_message_fibocom_at_command_set_new (buffer->len, (const guint8 *)buffer->data, NULL); + mbim_device_command (mm_port_mbim_peek_device (MM_PORT_MBIM (self)), + request, + timeout_seconds, + cancellable, + (GAsyncReadyCallback)at_command_ready, + task); +} + +/*****************************************************************************/ + +MMPortMbimFibocom * +mm_port_mbim_fibocom_new (const gchar *name, + MMPortSubsys subsys) +{ + return MM_PORT_MBIM_FIBOCOM (g_object_new (MM_TYPE_PORT_MBIM_FIBOCOM, + MM_PORT_DEVICE, name, + MM_PORT_SUBSYS, subsys, + MM_PORT_TYPE, MM_PORT_TYPE_MBIM, + NULL)); +} + +static void +mm_port_mbim_fibocom_init (MMPortMbimFibocom *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_PORT_MBIM_FIBOCOM, MMPortMbimFibocomPrivate); + self->priv->at_over_mbim = FEATURE_SUPPORT_UNKNOWN; +} + +static void +finalize (GObject *object) +{ + MMPortMbimFibocom *self = MM_PORT_MBIM_FIBOCOM (object); + + if (self->priv->parser) + mm_serial_parser_v1_destroy (self->priv->parser); + + G_OBJECT_CLASS (mm_port_mbim_fibocom_parent_class)->finalize (object); +} + +static void +iface_port_at_init (MMIfacePortAt *iface) +{ + iface->check_support = iface_port_at_check_support; + iface->command = iface_port_at_command; + iface->command_finish = iface_port_at_command_finish; +} + +static void +mm_port_mbim_fibocom_class_init (MMPortMbimFibocomClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (MMPortMbimFibocomPrivate)); + + object_class->finalize = finalize; +} diff --git a/src/plugins/fibocom/mm-port-mbim-fibocom.h b/src/plugins/fibocom/mm-port-mbim-fibocom.h new file mode 100644 index 00000000..f7104cd6 --- /dev/null +++ b/src/plugins/fibocom/mm-port-mbim-fibocom.h @@ -0,0 +1,59 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details: + * + * Copyright (C) 2024 Google, Inc. + */ + +#ifndef MM_PORT_MBIM_FIBOCOM_H +#define MM_PORT_MBIM_FIBOCOM_H + +#include <config.h> + +#include <glib.h> +#include <glib-object.h> +#include <gio/gio.h> + +#include <libmbim-glib.h> + +#if defined WITH_QMI +# include <libqmi-glib.h> +#endif + +#include "mm-port-mbim.h" + +#define MM_TYPE_PORT_MBIM_FIBOCOM (mm_port_mbim_fibocom_get_type ()) +#define MM_PORT_MBIM_FIBOCOM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PORT_MBIM_FIBOCOM, MMPortMbimFibocom)) +#define MM_PORT_MBIM_FIBOCOM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PORT_MBIM_FIBOCOM, MMPortMbimFibocomClass)) +#define MM_IS_PORT_MBIM_FIBOCOM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PORT_MBIM_FIBOCOM)) +#define MM_IS_PORT_MBIM_FIBOCOM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PORT_MBIM_FIBOCOM)) +#define MM_PORT_MBIM_FIBOCOM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PORT_MBIM_FIBOCOM, MMPortMbimFibocomClass)) + +typedef struct _MMPortMbimFibocom MMPortMbimFibocom; +typedef struct _MMPortMbimFibocomClass MMPortMbimFibocomClass; +typedef struct _MMPortMbimFibocomPrivate MMPortMbimFibocomPrivate; + +struct _MMPortMbimFibocom { + MMPortMbim parent; + MMPortMbimFibocomPrivate *priv; +}; + +struct _MMPortMbimFibocomClass { + MMPortMbimClass parent; +}; + +GType mm_port_mbim_fibocom_get_type (void); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMPortMbimFibocom, g_object_unref) + +MMPortMbimFibocom *mm_port_mbim_fibocom_new (const gchar *name, + MMPortSubsys subsys); + +#endif /* MM_PORT_MBIM_FIBOCOM_H */ diff --git a/src/plugins/fibocom/mm-shared-fibocom.c b/src/plugins/fibocom/mm-shared-fibocom.c index 50ac892e..562e1f79 100644 --- a/src/plugins/fibocom/mm-shared-fibocom.c +++ b/src/plugins/fibocom/mm-shared-fibocom.c @@ -28,6 +28,7 @@ #include "mm-iface-modem.h" #include "mm-iface-modem-3gpp.h" #include "mm-shared-fibocom.h" +#include "mm-port-mbim-fibocom.h" #include "mm-base-modem-at.h" /*****************************************************************************/ @@ -83,6 +84,40 @@ get_private (MMSharedFibocom *self) /*****************************************************************************/ +MMPort * +mm_shared_fibocom_create_usbmisc_port (MMBaseModem *self, + const gchar *name, + MMPortType ptype) +{ + Private *priv; + + priv = get_private (MM_SHARED_FIBOCOM (self)); + if (ptype == MM_PORT_TYPE_MBIM) { + mm_obj_dbg (self, "creating fibocom-specific MBIM port..."); + return MM_PORT (mm_port_mbim_fibocom_new (name, MM_PORT_SUBSYS_USBMISC)); + } + + return priv->class_parent->create_usbmisc_port (self, name, ptype); +} + +MMPort * +mm_shared_fibocom_create_wwan_port (MMBaseModem *self, + const gchar *name, + MMPortType ptype) +{ + Private *priv; + + priv = get_private (MM_SHARED_FIBOCOM (self)); + if (ptype == MM_PORT_TYPE_MBIM) { + mm_obj_dbg (self, "creating fibocom-specific MBIM port..."); + return MM_PORT (mm_port_mbim_fibocom_new (name, MM_PORT_SUBSYS_WWAN)); + } + + return priv->class_parent->create_wwan_port (self, name, ptype); +} + +/*****************************************************************************/ + void mm_shared_fibocom_setup_ports (MMBroadbandModem *self) { diff --git a/src/plugins/fibocom/mm-shared-fibocom.h b/src/plugins/fibocom/mm-shared-fibocom.h index ac2adb3b..cd763937 100644 --- a/src/plugins/fibocom/mm-shared-fibocom.h +++ b/src/plugins/fibocom/mm-shared-fibocom.h @@ -48,6 +48,13 @@ GType mm_shared_fibocom_get_type (void); void mm_shared_fibocom_setup_ports (MMBroadbandModem *self); +MMPort *mm_shared_fibocom_create_usbmisc_port (MMBaseModem *self, + const gchar *name, + MMPortType ptype); +MMPort *mm_shared_fibocom_create_wwan_port (MMBaseModem *self, + const gchar *name, + MMPortType ptype); + void mm_shared_fibocom_set_initial_eps_bearer_settings (MMIfaceModem3gpp *self, MMBearerProperties *config, GAsyncReadyCallback callback, diff --git a/src/plugins/meson.build b/src/plugins/meson.build index dd8fd131..30379fb4 100644 --- a/src/plugins/meson.build +++ b/src/plugins/meson.build @@ -73,6 +73,7 @@ if plugins_shared['fibocom'] c_args = '-DMM_MODULE_NAME="shared-fibocom"' sources = files( + 'fibocom/mm-port-mbim-fibocom.c', 'fibocom/mm-shared.c', 'fibocom/mm-shared-fibocom.c', ) diff --git a/src/plugins/mtk/mm-broadband-modem-mbim-mtk-fibocom.c b/src/plugins/mtk/mm-broadband-modem-mbim-mtk-fibocom.c index 08d5441a..67ef8dcf 100644 --- a/src/plugins/mtk/mm-broadband-modem-mbim-mtk-fibocom.c +++ b/src/plugins/mtk/mm-broadband-modem-mbim-mtk-fibocom.c @@ -316,9 +316,12 @@ static void mm_broadband_modem_mbim_mtk_fibocom_class_init (MMBroadbandModemMbimMtkFibocomClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + MMBaseModemClass *base_modem_class = MM_BASE_MODEM_CLASS (klass); MMBroadbandModemMbimClass *broadband_modem_mbim_class = MM_BROADBAND_MODEM_MBIM_CLASS (klass); g_type_class_add_private (object_class, sizeof (MMBroadbandModemMbimMtkFibocomPrivate)); + base_modem_class->create_usbmisc_port = mm_shared_fibocom_create_usbmisc_port; + base_modem_class->create_wwan_port = mm_shared_fibocom_create_wwan_port; broadband_modem_mbim_class->normalize_nw_error = normalize_nw_error; } |