fibocom: create custom MBIM port object with potential AT support
This commit is contained in:
committed by
Aleksander Morgado
parent
586f98f71d
commit
c66a6b89ec
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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',
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user