aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dan@ioncontrol.co>2025-05-09 21:34:26 -0500
committerDan Williams <dan@ioncontrol.co>2025-05-09 21:34:26 -0500
commitc99c300ad5fa350d0d2269ffde868063d5fb92ce (patch)
treee7331cd0736ab0d005717e76bfb0f3351e6f9b74
parentd165d61a9515061837ac12054d15dbeaeb134adf (diff)
parent4cae0406452ef4621aa7cc73f9d7a54db2ca0fb1 (diff)
Merge request !1235 from 'intel-rpc-xmm7360'
intel: implement support for RPC-powered xmm7360 https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1235
l---------build-aux/templates/mm-intel-enums-types.c.template1
l---------build-aux/templates/mm-intel-enums-types.h.template1
-rw-r--r--data/dispatcher-fcc-unlock/8086:7360131
-rw-r--r--data/dispatcher-fcc-unlock/meson.build1
-rw-r--r--src/plugins/intel/mm-bearer-xmm7360.c766
-rw-r--r--src/plugins/intel/mm-bearer-xmm7360.h56
-rw-r--r--src/plugins/intel/mm-broadband-modem-xmm7360-rpc.c577
-rw-r--r--src/plugins/intel/mm-broadband-modem-xmm7360-rpc.h173
-rw-r--r--src/plugins/intel/mm-broadband-modem-xmm7360.c1229
-rw-r--r--src/plugins/intel/mm-broadband-modem-xmm7360.h71
-rw-r--r--src/plugins/intel/mm-plugin-intel.c16
-rw-r--r--src/plugins/intel/mm-port-serial-xmmrpc-xmm7360.c750
-rw-r--r--src/plugins/intel/mm-port-serial-xmmrpc-xmm7360.h590
-rw-r--r--src/plugins/intel/mm-sim-xmm7360.c445
-rw-r--r--src/plugins/intel/mm-sim-xmm7360.h68
-rw-r--r--src/plugins/meson.build40
16 files changed, 4909 insertions, 6 deletions
diff --git a/build-aux/templates/mm-intel-enums-types.c.template b/build-aux/templates/mm-intel-enums-types.c.template
new file mode 120000
index 00000000..6a247265
--- /dev/null
+++ b/build-aux/templates/mm-intel-enums-types.c.template
@@ -0,0 +1 @@
+mm-enumflags-types.c.template \ No newline at end of file
diff --git a/build-aux/templates/mm-intel-enums-types.h.template b/build-aux/templates/mm-intel-enums-types.h.template
new file mode 120000
index 00000000..7fada6bc
--- /dev/null
+++ b/build-aux/templates/mm-intel-enums-types.h.template
@@ -0,0 +1 @@
+mm-enumflags-types.h.template \ No newline at end of file
diff --git a/data/dispatcher-fcc-unlock/8086:7360 b/data/dispatcher-fcc-unlock/8086:7360
new file mode 100644
index 00000000..d6116dd8
--- /dev/null
+++ b/data/dispatcher-fcc-unlock/8086:7360
@@ -0,0 +1,131 @@
+#!/bin/bash
+
+# SPDX-License-Identifier: CC0-1.0
+# 2024 Thomas Vogt
+#
+# RPC-powered Intel XMM7360 (8086:7360) FCC unlock
+
+if [[ "$FCC_UNLOCK_DEBUG_LOG" == '1' ]]; then
+ exec 3>&1 4>&2
+ trap 'exec 2>&4 1>&3' 0 1 2 3
+ exec 1>>/var/log/mm-xmm7360-fcc.log 2>&1
+fi
+
+# require program name and at least 2 arguments
+[ $# -lt 2 ] && exit 1
+
+# first argument is DBus path, not needed here
+shift
+
+# second and next arguments are control port names
+for PORT in "$@"; do
+ # support for XMM7360 has been added in 5.18
+ # match port type, assuming Linux 5.14 and newer
+ grep -q XMMRPC "/sys/class/wwan/$PORT/type" 2>/dev/null && {
+ XMMRPC_PORT=$PORT
+ break
+ }
+done
+
+# fail if no XMMRPC port exposed
+[ -n "$XMMRPC_PORT" ] || exit 2
+
+DEVICE=/dev/${XMMRPC_PORT}
+
+log() {
+ echo "$1"
+}
+
+error() {
+ echo "$1" >&2
+}
+
+reverseHexEndianness() {
+ num="$1"
+ printf "%s" "${num:6:2}${num:4:2}${num:2:2}${num:0:2}"
+}
+
+littleEndianToDec() {
+ printf "%d" "0x$1"
+}
+
+bigEndianToDec() {
+ littleEndianToDec "$(reverseHexEndianness "$1")"
+}
+
+readNBytesAsHex() {
+ data=$(head "-c$1" <&99 | xxd -p -c0 | tr -d '\n')
+ printf "%s" "$data"
+}
+
+writeHexAsBinary() {
+ printf "%s" "$1" | xxd -r -p >&99
+}
+
+readResponseAsHex() {
+ length_hex=$(readNBytesAsHex 4)
+ length=$(bigEndianToDec "$length_hex")
+ content=$(readNBytesAsHex $length)
+ printf "%s" "$length_hex$content"
+}
+
+rpc_command() {
+ exec 99<>"$DEVICE"
+ writeHexAsBinary $1
+ answer=$(readResponseAsHex) # ignore "async-ack" response
+ answer=$(readResponseAsHex)
+ printf "%s" "$answer"
+ exec 99>&-
+}
+
+VENDOR_ID_HASH="3df8c719"
+
+for i in {1..3}; do
+ log "Attempt #${i} to unlock WWAN modem"
+
+ log "Requesting FCC lock state from modem"
+ # --> (async) csi-fcc-lock-query-req
+ RESP=$(rpc_command "1c00000002040000001c02040000018e11000101020411000101020400000000")
+ MODE=$(littleEndianToDec "${RESP: -8}")
+ STATE=$(littleEndianToDec "${RESP: -20:8}")
+
+ log "Got response from modem: state=$STATE, mode=$MODE"
+
+ if [ "$MODE" = "0" ]; then
+ log "FCC lock is deactivated, nothing to do."
+ exit 0
+ fi
+
+ if [ "$STATE" != "0" ]; then
+ log "FCC already unlocked, nothing to do."
+ exit 0
+ fi
+
+ log "Requesting challenge from modem"
+ # --> (async) csi-fcc-lock-gen-challenge-req
+ RESP=$(rpc_command "1c00000002040000001c02040000019011000101020411000101020400000000")
+ HEX_CHALLENGE=$(printf "%s" "${RESP: -8}")
+
+ log "Got challenge from modem: $HEX_CHALLENGE"
+ REVERSE_HEX_CHALLENGE=$(reverseHexEndianness "${HEX_CHALLENGE}")
+ COMBINED_CHALLENGE="${REVERSE_HEX_CHALLENGE}${VENDOR_ID_HASH}"
+ RESPONSE_HASH=$(printf "%s" "$COMBINED_CHALLENGE" | xxd -r -p | sha256sum | cut -d ' ' -f 1)
+ REVERSED_RESPONSE=$(reverseHexEndianness "${RESPONSE_HASH:0:8}")
+
+ log "Sending hash to modem: $REVERSED_RESPONSE"
+ # --> (async) csi-fcc-lock-ver-challenge-req
+ RESP=$(rpc_command "1c00000002040000001c020400000192110001010204110001010204${REVERSED_RESPONSE}")
+ UNLOCK_RESPONSE=$(littleEndianToDec "${RESP: -8}")
+
+ if [ "$UNLOCK_RESPONSE" = "0" ]; then
+ error "Unlock failed."
+ else
+ log "FCC unlock successful (response $UNLOCK_RESPONSE)"
+ exit 0
+ fi
+
+ sleep 0.5
+done
+
+exit 2
+
diff --git a/data/dispatcher-fcc-unlock/meson.build b/data/dispatcher-fcc-unlock/meson.build
index b834dd56..b82889cd 100644
--- a/data/dispatcher-fcc-unlock/meson.build
+++ b/data/dispatcher-fcc-unlock/meson.build
@@ -15,6 +15,7 @@ examples = files(
'1199',
'14c3',
'2c7c',
+ '8086:7360',
)
install_data(
diff --git a/src/plugins/intel/mm-bearer-xmm7360.c b/src/plugins/intel/mm-bearer-xmm7360.c
new file mode 100644
index 00000000..10dd2c26
--- /dev/null
+++ b/src/plugins/intel/mm-bearer-xmm7360.c
@@ -0,0 +1,766 @@
+/* -*- 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) 2019 James Wah
+ * Copyright (C) 2020 Marinus Enzinger <marinus@enzingerm.de>
+ * Copyright (C) 2023 Shane Parslow
+ * Copyright (C) 2024 Thomas Vogt
+ */
+
+#include <ModemManager.h>
+#define _LIBMM_INSIDE_MM
+#include <libmm-glib.h>
+
+#include "mm-log-object.h"
+
+#include "mm-bearer-xmm7360.h"
+#include "mm-broadband-modem-xmm7360.h"
+#include "mm-broadband-modem-xmm7360-rpc.h"
+#include "mm-port-serial-xmmrpc-xmm7360.h"
+
+G_DEFINE_TYPE (MMBearerXmm7360, mm_bearer_xmm7360, MM_TYPE_BASE_BEARER)
+
+struct _MMBearerXmm7360Private {
+ gboolean is_connected;
+};
+
+/*****************************************************************************/
+/* Connect */
+
+typedef struct {
+ MMPort *data;
+ MMPortSerialXmmrpcXmm7360 *port;
+ guint unsol_handler_id;
+ gboolean is_attach_allowed;
+ gboolean is_attached;
+ guint attach_attempts;
+ guint attach_allowed_timeout_id;
+ Xmm7360RpcResponse *ps_connect_response;
+ GInetAddress *ip;
+ GPtrArray *dns;
+} ConnectContext;
+
+static void
+connect_context_free (ConnectContext *ctx)
+{
+ if (ctx->ps_connect_response)
+ xmm7360_rpc_response_free (ctx->ps_connect_response);
+ if (ctx->attach_allowed_timeout_id)
+ g_source_remove (ctx->attach_allowed_timeout_id);
+ if (ctx->unsol_handler_id) {
+ mm_port_serial_xmmrpc_xmm7360_enable_unsolicited_msg_handler (
+ ctx->port,
+ ctx->unsol_handler_id,
+ FALSE);
+ }
+ g_clear_object (&ctx->ip);
+ if (ctx->dns)
+ g_ptr_array_free (ctx->dns, TRUE);
+ mm_port_serial_close (MM_PORT_SERIAL (ctx->port));
+ g_clear_object (&ctx->port);
+ g_clear_object (&ctx->data);
+ g_slice_free (ConnectContext, ctx);
+}
+
+static MMBearerConnectResult *
+connect_finish (MMBaseBearer *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_pointer (G_TASK (res), error);
+}
+
+static void
+xmm7360_connect_apn_ready (MMBroadbandModemXmm7360 *modem,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ MMBearerXmm7360 *self;
+ MMBearerConnectResult *connect_result;
+
+ self = g_task_get_source_object (task);
+
+ connect_result = g_task_propagate_pointer (G_TASK (res), &error);
+ if (error) {
+ g_task_return_error (task, error);
+ } else {
+ self->priv->is_connected = TRUE;
+ g_task_return_pointer (task,
+ connect_result,
+ (GDestroyNotify)mm_bearer_connect_result_unref);
+ }
+ g_object_unref (task);
+}
+
+static void
+ps_connect_setup_ready (MMBroadbandModemXmm7360 *modem,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ ConnectContext *ctx;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+ g_autoptr(MMBearerIpConfig) ip_config = NULL;
+ g_autofree gchar *ipaddr = NULL;
+ g_auto(GStrv) dnsaddrs = NULL;
+ GInetAddress *dns;
+ guint i;
+ guint n;
+
+ ctx = g_task_get_task_data (task);
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (modem, res, &error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ /* we get static IPs to set */
+ ip_config = mm_bearer_ip_config_new ();
+ ipaddr = g_inet_address_to_string (ctx->ip);
+ dnsaddrs = g_new0 (gchar *, ctx->dns->len + 1);
+ for (i = 0, n = 0; i < ctx->dns->len; i++) {
+ dns = g_ptr_array_index (ctx->dns, i);
+ if (g_inet_address_get_family (dns) == G_SOCKET_FAMILY_IPV4
+ && !g_inet_address_get_is_any (dns)) {
+ dnsaddrs[n++] = g_inet_address_to_string (dns);
+ }
+ }
+ mm_bearer_ip_config_set_method (ip_config, MM_BEARER_IP_METHOD_STATIC);
+ mm_bearer_ip_config_set_address (ip_config, ipaddr);
+ mm_bearer_ip_config_set_dns (ip_config, (const gchar **)dnsaddrs);
+
+ g_task_return_pointer (task,
+ mm_bearer_connect_result_new (ctx->data, ip_config, NULL),
+ (GDestroyNotify)mm_bearer_connect_result_unref);
+ g_object_unref (task);
+}
+
+static void
+ps_connect_to_datachannel_ready (MMBroadbandModemXmm7360 *modem,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ ConnectContext *ctx;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+ g_autoptr(GByteArray) connect_setup_body = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (modem, res, &error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ connect_setup_body = g_byte_array_new ();
+ g_byte_array_append (connect_setup_body,
+ ctx->ps_connect_response->body->data,
+ ctx->ps_connect_response->body->len - 6);
+ g_byte_array_append (connect_setup_body,
+ response->body->data,
+ response->body->len);
+ xmm7360_byte_array_append_asn_int4 (connect_setup_body, 0);
+
+ mm_broadband_modem_xmm7360_rpc_command_full (modem,
+ ctx->port,
+ XMM7360_RPC_CALL_UTA_RPC_PS_CONNECT_SETUP_REQ,
+ FALSE,
+ connect_setup_body,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)ps_connect_setup_ready,
+ task);
+}
+
+static GByteArray *
+pack_uta_rpc_ps_connect_to_datachannel_req (void)
+{
+ static const Xmm7360RpcMsgArg args[] = {
+ /* size is length of string + null byte */
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = "/sioscc/PCIE/IOSM/IPS/0" }, 24 },
+ { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN },
+ };
+ return xmm7360_rpc_args_to_byte_array (args);
+}
+
+static void
+ps_connect_ready (MMBroadbandModemXmm7360 *modem,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ ConnectContext *ctx;
+ Xmm7360RpcResponse *response = NULL;
+ g_autoptr(GByteArray) body = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (modem, res, &error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ xmm7360_rpc_response_free (response);
+ return;
+ }
+
+ ctx->ps_connect_response = response;
+
+ body = pack_uta_rpc_ps_connect_to_datachannel_req ();
+
+ mm_broadband_modem_xmm7360_rpc_command_full (modem,
+ ctx->port,
+ XMM7360_RPC_CALL_UTA_RPC_PS_CONNECT_TO_DATACHANNEL_REQ,
+ FALSE,
+ body,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)ps_connect_to_datachannel_ready,
+ task);
+}
+
+static GByteArray *
+pack_uta_ms_call_ps_connect_req (void)
+{
+ static const Xmm7360RpcMsgArg args[] = {
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 6 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN },
+ };
+ return xmm7360_rpc_args_to_byte_array (args);
+}
+
+static void
+get_dns_ready (MMBroadbandModemXmm7360 *modem,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ ConnectContext *ctx;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+ Xmm7360RpcMsgArg *arg;
+ guint i;
+ g_autoptr(GByteArray) body = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (modem, res, &error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ for (i = 1; i < 17; i += 2) {
+ /* iterate over pairs of args: IP [i] and IP format (v4(1) or v6(2) or MISSING(0)) [i+1] */
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, i + 1);
+ if (XMM7360_RPC_MSG_ARG_GET_INT (arg) == 1) {
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, i);
+ g_assert (arg->size >= 4);
+ g_ptr_array_add (ctx->dns, g_inet_address_new_from_bytes ((const guint8 *)arg->value.string,
+ G_SOCKET_FAMILY_IPV4));
+ } else if (XMM7360_RPC_MSG_ARG_GET_INT (arg) == 2) {
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, i);
+ g_assert (arg->size >= 16);
+ g_ptr_array_add (ctx->dns, g_inet_address_new_from_bytes ((const guint8 *)arg->value.string,
+ G_SOCKET_FAMILY_IPV6));
+ }
+ }
+
+ body = pack_uta_ms_call_ps_connect_req ();
+
+ mm_broadband_modem_xmm7360_rpc_command_full (modem,
+ ctx->port,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_CONNECT_REQ,
+ TRUE,
+ body,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)ps_connect_ready,
+ task);
+}
+
+static GByteArray *
+pack_uta_ms_call_ps_get_negotiated_dns_req (void)
+{
+ static const Xmm7360RpcMsgArg args[] = {
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN },
+ };
+ return xmm7360_rpc_args_to_byte_array (args);
+}
+
+static void
+get_ip_addr_ready (MMBroadbandModemXmm7360 *modem,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ ConnectContext *ctx;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+ Xmm7360RpcMsgArg *arg;
+ gint i;
+ guint32 *ip_bytes;
+ g_autoptr(GByteArray) body = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (modem, res, &error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 1);
+ if (arg->size < 12) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "The IP address field is invalid (too short)");
+ g_object_unref (task);
+ return;
+ }
+
+ /* the STRING arg contains three IP addresses, we only use the last non-zero address */
+ ip_bytes = (guint32 *)arg->value.string;
+ for (i = 2; i >= 0; i--) {
+ if (ip_bytes[i] != 0) {
+ ctx->ip = g_inet_address_new_from_bytes ((const guint8 *)&ip_bytes[i],
+ G_SOCKET_FAMILY_IPV4);
+ break;
+ }
+ }
+
+ if (ctx->ip == NULL) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "The IP address field is invalid (all zeros)");
+ g_object_unref (task);
+ return;
+ }
+
+ body = pack_uta_ms_call_ps_get_negotiated_dns_req ();
+
+ mm_broadband_modem_xmm7360_rpc_command_full (modem,
+ ctx->port,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_GET_NEGOTIATED_DNS_REQ,
+ TRUE,
+ body,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)get_dns_ready,
+ task);
+}
+
+static GByteArray *
+pack_uta_ms_call_ps_get_neg_ip_addr_req (void)
+{
+ static const Xmm7360RpcMsgArg args[] = {
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN },
+ };
+ return xmm7360_rpc_args_to_byte_array (args);
+}
+
+static gboolean
+get_ip_config (GTask *task)
+{
+ ConnectContext *ctx;
+ MMBroadbandModemXmm7360 *modem;
+ g_autoptr(GByteArray) body = NULL;
+
+ if (g_cancellable_is_cancelled (g_task_get_cancellable (task))) {
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED,
+ "operation has been cancelled");
+ g_object_unref (task);
+ return G_SOURCE_REMOVE;
+ }
+
+ ctx = g_task_get_task_data (task);
+
+ modem = g_task_get_source_object (task);
+
+ body = pack_uta_ms_call_ps_get_neg_ip_addr_req ();
+
+ mm_broadband_modem_xmm7360_rpc_command_full (modem,
+ ctx->port,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_GET_NEG_IP_ADDR_REQ,
+ TRUE,
+ body,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)get_ip_addr_ready,
+ task);
+
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean
+attach_allowed_timeout_cb (GTask *task)
+{
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Connecting timed out (waiting for attach-allowed)");
+ g_object_unref (task);
+ return G_SOURCE_REMOVE;
+}
+
+static void net_attach_command (GTask *task);
+
+static void
+net_attach_command_ready (MMBroadbandModemXmm7360 *modem,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ ConnectContext *ctx;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+ Xmm7360RpcMsgArg *arg;
+ gint status;
+
+ ctx = g_task_get_task_data (task);
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (modem, res, &error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (response->content->len < 2) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "The response for net-attach is invalid (too short)");
+ g_object_unref (task);
+ return;
+ }
+
+ /* status code */
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 1);
+ g_assert (arg->type == XMM7360_RPC_MSG_ARG_TYPE_LONG);
+ status = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ if (status != (gint32)0xffffffff) {
+ ctx->is_attached = TRUE;
+ /* give the modem a second before requesting the IP */
+ g_timeout_add_seconds (1, (GSourceFunc)get_ip_config, task);
+ } else if (ctx->is_attach_allowed && ctx->attach_attempts < 2) {
+ /* immediately try a second time if it should have been allowed */
+ ctx->is_attach_allowed = FALSE;
+ net_attach_command (task);
+ } else if (ctx->attach_attempts < 3) {
+ /* give up if we do not receive an attach-allowed unsolicited message within 5 seconds */
+ ctx->attach_allowed_timeout_id = g_timeout_add_seconds (5, (GSourceFunc)attach_allowed_timeout_cb, task);
+ } else {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Giving up on attach-net operation after three failed attempts");
+ g_object_unref (task);
+ }
+}
+
+static GByteArray *
+pack_uta_ms_net_attach_req (void)
+{
+ static const Xmm7360RpcMsgArg args[] = {
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_SHORT, { .s = 0xffff } },
+ { XMM7360_RPC_MSG_ARG_TYPE_SHORT, { .s = 0xffff } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN },
+ };
+ return xmm7360_rpc_args_to_byte_array (args);
+}
+
+static void
+net_attach_command (GTask *task)
+{
+ ConnectContext *ctx;
+ MMBroadbandModemXmm7360 *modem;
+ g_autoptr(GByteArray) body = NULL;
+
+ ctx = g_task_get_task_data (task);
+ ctx->attach_attempts++;
+
+ modem = g_task_get_source_object (task);
+
+ body = pack_uta_ms_net_attach_req ();
+
+ mm_broadband_modem_xmm7360_rpc_command_full (modem,
+ ctx->port,
+ XMM7360_RPC_CALL_UTA_MS_NET_ATTACH_REQ,
+ TRUE,
+ body,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)net_attach_command_ready,
+ task);
+}
+
+static gboolean
+connect_unsol_handler (MMPortSerialXmmrpcXmm7360 *port,
+ Xmm7360RpcResponse *response,
+ GTask *task)
+{
+ Xmm7360RpcMsgArg *arg;
+ ConnectContext *ctx;
+
+ if (response->unsol_id != XMM7360_RPC_UNSOL_UTA_MS_NET_IS_ATTACH_ALLOWED_IND_CB) {
+ return FALSE;
+ }
+
+ if (response->content->len <= 2) {
+ mm_obj_dbg (port, "Ignoring invalid is-attach-allowed message (too short)");
+ return TRUE;
+ }
+
+ ctx = g_task_get_task_data (task);
+
+ if (ctx->is_attached) {
+ /* already attached, ignore the attach-allowed status message */
+ return TRUE;
+ }
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 2);
+ if (XMM7360_RPC_MSG_ARG_GET_INT (arg)) {
+ ctx->is_attach_allowed = TRUE;
+ if (ctx->attach_allowed_timeout_id) {
+ g_source_remove (ctx->attach_allowed_timeout_id);
+ ctx->attach_allowed_timeout_id = 0;
+ /* attach-net is allowed now, retry */
+ net_attach_command (task);
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+xmm7360_connect (MMBroadbandModemXmm7360 *modem,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ GTask *task;
+ ConnectContext *ctx;
+
+ task = g_task_new (modem, cancellable, callback, user_data);
+
+ ctx = g_slice_new0 (ConnectContext);
+ ctx->port = mm_broadband_modem_xmm7360_get_port_xmmrpc (modem);
+ ctx->dns = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
+ g_task_set_task_data (task, ctx, (GDestroyNotify)connect_context_free);
+
+ /* Grab a data port */
+ ctx->data = mm_base_modem_get_best_data_port (MM_BASE_MODEM (modem), MM_PORT_TYPE_NET);
+ if (!ctx->data) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND,
+ "No valid data port found to launch connection");
+ g_object_unref (task);
+ return;
+ }
+
+ /* Open XMMRPC port for initialization */
+ if (!mm_port_serial_open (MM_PORT_SERIAL (ctx->port), &error)) {
+ g_prefix_error (&error, "Couldn't open XMMRPC port for connection setup: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ ctx->unsol_handler_id = mm_port_serial_xmmrpc_xmm7360_add_unsolicited_msg_handler (
+ ctx->port,
+ (MMPortSerialXmmrpcXmm7360UnsolicitedMsgFn)connect_unsol_handler,
+ task,
+ NULL);
+
+ net_attach_command (task);
+}
+
+static void
+connect (MMBaseBearer *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ g_autoptr(MMBaseModem) modem = NULL;
+
+ /* Get the owner modem object */
+ g_object_get (self,
+ MM_BASE_BEARER_MODEM, &modem,
+ NULL);
+ g_assert (modem != NULL);
+
+ task = g_task_new (self, cancellable, callback, user_data);
+
+ /* the connect routine is independent of the bearer object */
+ xmm7360_connect (MM_BROADBAND_MODEM_XMM7360 (modem),
+ cancellable,
+ (GAsyncReadyCallback)xmm7360_connect_apn_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* Disconnect */
+
+static gboolean
+disconnect_finish (MMBaseBearer *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+disconnect_sequence_ready (MMBroadbandModem *modem,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+
+ response = mm_broadband_modem_xmm7360_rpc_sequence_finish (MM_BROADBAND_MODEM_XMM7360 (modem),
+ res,
+ &error);
+
+ if (error) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Failed to complete disconnect sequence: %s", error->message);
+ g_object_unref (task);
+ return;
+ }
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static const MMBroadbandModemXmm7360RpcCommand disconnect_sequence[] = {
+ {
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_DEACTIVATE_REQ,
+ TRUE,
+ (Xmm7360RpcMsgArg[]) {
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN },
+ },
+ 3,
+ FALSE,
+ mm_broadband_modem_xmm7360_rpc_response_processor_continue_on_success
+ /* response will be: L(0x0) L(0x0) L(0x5dffffff) L(0x0) (meaning unknown) */
+ },
+ {
+ XMM7360_RPC_CALL_UTA_RPC_PS_CONNECT_RELEASE_REQ,
+ FALSE,
+ (Xmm7360RpcMsgArg[]) {
+ /* the meaning of this value is unknown, but it is used by the Windows driver */
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0x20017 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN },
+ },
+ 3,
+ FALSE,
+ mm_broadband_modem_xmm7360_rpc_response_processor_final
+ /* response will be: L(0x0) (meaning unknown) */
+ },
+ { 0 }
+};
+
+static void
+disconnect (MMBaseBearer *bearer,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ g_autoptr(MMBaseModem) modem = NULL;
+ g_autoptr(MMPortSerialXmmrpcXmm7360) port = NULL;
+
+ task = g_task_new (bearer, NULL, callback, user_data);
+
+ /* Get the owner modem object */
+ g_object_get (bearer, MM_BASE_BEARER_MODEM, &modem, NULL);
+ g_assert (modem != NULL);
+
+ port = mm_broadband_modem_xmm7360_get_port_xmmrpc (MM_BROADBAND_MODEM_XMM7360 (modem));
+
+ mm_broadband_modem_xmm7360_rpc_sequence_full (MM_BROADBAND_MODEM_XMM7360 (modem),
+ port,
+ disconnect_sequence,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)disconnect_sequence_ready,
+ task);
+}
+
+/*****************************************************************************/
+
+MMBaseBearer *
+mm_bearer_xmm7360_new (MMBroadbandModemXmm7360 *modem,
+ MMBearerProperties *config)
+{
+ MMBaseBearer *base_bearer;
+ MMBearerXmm7360 *bearer;
+
+ /* The Xmm7360 bearer inherits from MMBaseBearer (so it's not a MMBroadbandBearer)
+ * and that means that the object is not async-initable, so we just use
+ * g_object_new here */
+ bearer = g_object_new (MM_TYPE_BEARER_XMM7360,
+ MM_BASE_BEARER_MODEM, modem,
+ MM_BASE_BEARER_CONFIG, config,
+ NULL);
+
+ base_bearer = MM_BASE_BEARER (bearer);
+ /* Only export valid bearers */
+ mm_base_bearer_export (base_bearer);
+
+ return base_bearer;
+}
+
+static void
+mm_bearer_xmm7360_init (MMBearerXmm7360 *self)
+{
+ /* Initialize private data */
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ MM_TYPE_BEARER_XMM7360,
+ MMBearerXmm7360Private);
+}
+
+static void
+mm_bearer_xmm7360_class_init (MMBearerXmm7360Class *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMBaseBearerClass *base_bearer_class = MM_BASE_BEARER_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMBearerXmm7360Private));
+
+ base_bearer_class->connect = connect;
+ base_bearer_class->connect_finish = connect_finish;
+
+ base_bearer_class->disconnect = disconnect;
+ base_bearer_class->disconnect_finish = disconnect_finish;
+}
diff --git a/src/plugins/intel/mm-bearer-xmm7360.h b/src/plugins/intel/mm-bearer-xmm7360.h
new file mode 100644
index 00000000..3e39525c
--- /dev/null
+++ b/src/plugins/intel/mm-bearer-xmm7360.h
@@ -0,0 +1,56 @@
+/* -*- 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) 2019 James Wah
+ * Copyright (C) 2020 Marinus Enzinger <marinus@enzingerm.de>
+ * Copyright (C) 2023 Shane Parslow
+ * Copyright (c) 2024 Thomas Vogt
+ */
+
+#ifndef MM_BEARER_XMM7360_H
+#define MM_BEARER_XMM7360_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#define _LIBMM_INSIDE_MM
+#include <libmm-glib.h>
+
+#include "mm-base-bearer.h"
+#include "mm-broadband-modem-xmm7360.h"
+
+#define MM_TYPE_BEARER_XMM7360 (mm_bearer_xmm7360_get_type ())
+#define MM_BEARER_XMM7360(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BEARER_XMM7360, MMBearerXmm7360))
+#define MM_BEARER_XMM7360_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BEARER_XMM7360, MMBearerXmm7360Class))
+#define MM_IS_BEARER_XMM7360(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BEARER_XMM7360))
+#define MM_IS_BEARER_XMM7360_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BEARER_XMM7360))
+#define MM_BEARER_XMM7360_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BEARER_XMM7360, MMBearerXmm7360Class))
+
+typedef struct _MMBearerXmm7360 MMBearerXmm7360;
+typedef struct _MMBearerXmm7360Class MMBearerXmm7360Class;
+typedef struct _MMBearerXmm7360Private MMBearerXmm7360Private;
+
+struct _MMBearerXmm7360 {
+ MMBaseBearer parent;
+ MMBearerXmm7360Private *priv;
+};
+
+struct _MMBearerXmm7360Class {
+ MMBaseBearerClass parent;
+};
+
+GType mm_bearer_xmm7360_get_type (void);
+
+MMBaseBearer *mm_bearer_xmm7360_new (MMBroadbandModemXmm7360 *modem,
+ MMBearerProperties *config);
+
+#endif /* MM_BEARER_XMM7360_H */
diff --git a/src/plugins/intel/mm-broadband-modem-xmm7360-rpc.c b/src/plugins/intel/mm-broadband-modem-xmm7360-rpc.c
new file mode 100644
index 00000000..85bc009b
--- /dev/null
+++ b/src/plugins/intel/mm-broadband-modem-xmm7360-rpc.c
@@ -0,0 +1,577 @@
+/* -*- 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 Thomas Vogt
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <ModemManager.h>
+
+#include "mm-log-object.h"
+#include "mm-errors-types.h"
+
+#include "mm-broadband-modem-xmm7360-rpc.h"
+
+static gboolean
+abort_task_if_port_unusable (MMBroadbandModemXmm7360 *self,
+ MMPortSerialXmmrpcXmm7360 *port,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ /* If no port given, probably the port disappeared */
+ if (!port) {
+ g_task_return_new_error (task,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_NOT_FOUND,
+ "Cannot run sequence: port not given");
+ g_object_unref (task);
+ return FALSE;
+ }
+
+ /* Ensure we don't try to use a connected port */
+ if (mm_port_get_connected (MM_PORT (port))) {
+ g_task_return_new_error (task,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_CONNECTED,
+ "Cannot run sequence: port is connected");
+ g_object_unref (task);
+ return FALSE;
+ }
+
+ /* Ensure we have a port open during the sequence */
+ if (!mm_port_serial_open (MM_PORT_SERIAL (port), &error)) {
+ g_task_return_new_error (task,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_CONNECTED,
+ "Cannot run sequence: '%s'",
+ error->message);
+ g_error_free (error);
+ g_object_unref (task);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+parent_cancellable_cancelled (GCancellable *parent_cancellable,
+ GCancellable *cancellable)
+{
+ g_cancellable_cancel (cancellable);
+}
+
+/*****************************************************************************/
+/* RPC sequence handling */
+
+static void rpc_sequence_parse_response (MMPortSerialXmmrpcXmm7360 *port,
+ GAsyncResult *res,
+ GTask *task);
+
+typedef struct {
+ MMPortSerialXmmrpcXmm7360 *port;
+ gulong cancelled_id;
+ GCancellable *parent_cancellable;
+ const MMBroadbandModemXmm7360RpcCommand *current;
+ const MMBroadbandModemXmm7360RpcCommand *sequence;
+ guint next_command_wait_id;
+} RpcSequenceContext;
+
+static void
+rpc_sequence_context_free (RpcSequenceContext *ctx)
+{
+ mm_port_serial_close (MM_PORT_SERIAL (ctx->port));
+ g_object_unref (ctx->port);
+
+ if (ctx->parent_cancellable) {
+ g_cancellable_disconnect (ctx->parent_cancellable,
+ ctx->cancelled_id);
+ g_object_unref (ctx->parent_cancellable);
+ }
+
+ if (ctx->next_command_wait_id > 0) {
+ g_source_remove (ctx->next_command_wait_id);
+ ctx->next_command_wait_id = 0;
+ }
+
+ g_free (ctx);
+}
+
+Xmm7360RpcResponse *
+mm_broadband_modem_xmm7360_rpc_sequence_full_finish (MMBroadbandModemXmm7360 *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_pointer (G_TASK (res), error);
+}
+
+static gboolean
+rpc_sequence_next_command (GTask *task)
+{
+ RpcSequenceContext *ctx;
+ g_autoptr(GByteArray) body = NULL;
+
+ ctx = g_task_get_task_data (task);
+ ctx->next_command_wait_id = 0;
+
+ body = xmm7360_rpc_args_to_byte_array ((const Xmm7360RpcMsgArg *)ctx->current->body);
+
+ /* Schedule the next command in the probing group */
+ mm_port_serial_xmmrpc_xmm7360_command (
+ ctx->port,
+ ctx->current->callid,
+ ctx->current->is_async,
+ body,
+ ctx->current->timeout,
+ ctx->current->allow_cached,
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback)rpc_sequence_parse_response,
+ task);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+rpc_sequence_parse_response (MMPortSerialXmmrpcXmm7360 *port,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemXmm7360RpcResponseProcessorResult processor_result;
+ GError *result_error = NULL;
+ RpcSequenceContext *ctx;
+ Xmm7360RpcResponse *response = NULL;
+ g_autoptr(GError) command_error = NULL;
+
+ response = mm_port_serial_xmmrpc_xmm7360_command_finish (port, res, &command_error);
+
+ /* Cancelled? */
+ if (g_task_return_error_if_cancelled (task)) {
+ g_object_unref (task);
+ return;
+ }
+
+ ctx = g_task_get_task_data (task);
+ if (!ctx->current->response_processor)
+ processor_result = MM_BROADBAND_MODEM_XMM7360_RPC_RESPONSE_PROCESSOR_RESULT_CONTINUE;
+ else {
+ const MMBroadbandModemXmm7360RpcCommand *next = ctx->current + 1;
+
+ /* Response processor will tell us if we need to keep on the sequence */
+ processor_result = ctx->current->response_processor (g_task_get_source_object (task),
+ response,
+ next->callid ? FALSE : TRUE, /* Last command in sequence? */
+ command_error,
+ &result_error);
+ switch (processor_result) {
+ case MM_BROADBAND_MODEM_XMM7360_RPC_RESPONSE_PROCESSOR_RESULT_CONTINUE:
+ g_assert (!result_error);
+ if (response)
+ xmm7360_rpc_response_free (response);
+ break;
+ case MM_BROADBAND_MODEM_XMM7360_RPC_RESPONSE_PROCESSOR_RESULT_SUCCESS:
+ g_assert (!result_error);
+ break;
+ case MM_BROADBAND_MODEM_XMM7360_RPC_RESPONSE_PROCESSOR_RESULT_FAILURE:
+ /* On failure, complete with error right away */
+ g_assert (result_error);
+ if (response)
+ xmm7360_rpc_response_free (response);
+ g_task_return_error (task, result_error);
+ g_object_unref (task);
+ return;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ if (processor_result == MM_BROADBAND_MODEM_XMM7360_RPC_RESPONSE_PROCESSOR_RESULT_CONTINUE) {
+ ctx->current++;
+ if (ctx->current->callid) {
+ g_assert (!ctx->next_command_wait_id);
+ ctx->next_command_wait_id = g_timeout_add_seconds (ctx->current->wait_seconds,
+ (GSourceFunc) rpc_sequence_next_command,
+ task);
+ return;
+ }
+ /* On last command, end. */
+ }
+
+ g_task_return_pointer (task, response, (GDestroyNotify) xmm7360_rpc_response_free);
+ g_object_unref (task);
+}
+
+static void
+rpc_sequence_common (MMBroadbandModemXmm7360 *self,
+ MMPortSerialXmmrpcXmm7360 *port,
+ const MMBroadbandModemXmm7360RpcCommand *sequence,
+ GTask *task,
+ GCancellable *parent_cancellable)
+{
+ RpcSequenceContext *ctx;
+ g_autoptr(GByteArray) body = NULL;
+
+ /* Ensure that we have an open port */
+ if (!abort_task_if_port_unusable (self, port, task))
+ return;
+
+ /* Setup context */
+ ctx = g_new0 (RpcSequenceContext, 1);
+ ctx->port = g_object_ref (port);
+ ctx->current = ctx->sequence = sequence;
+
+ /* Ensure the cancellable that's already associated with the modem
+ * will also get cancelled if the modem wide-one gets cancelled */
+ if (parent_cancellable) {
+ GCancellable *cancellable;
+
+ cancellable = g_task_get_cancellable (task);
+ ctx->parent_cancellable = g_object_ref (parent_cancellable);
+ ctx->cancelled_id = g_cancellable_connect (ctx->parent_cancellable,
+ G_CALLBACK (parent_cancellable_cancelled),
+ cancellable,
+ NULL);
+ }
+
+ g_task_set_task_data (task, ctx, (GDestroyNotify)rpc_sequence_context_free);
+
+ body = xmm7360_rpc_args_to_byte_array ((const Xmm7360RpcMsgArg *)ctx->current->body);
+
+ /* Go on with the first one in the sequence */
+ mm_port_serial_xmmrpc_xmm7360_command (
+ ctx->port,
+ ctx->current->callid,
+ ctx->current->is_async,
+ body,
+ ctx->current->timeout,
+ ctx->current->allow_cached,
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback)rpc_sequence_parse_response,
+ task);
+}
+
+void
+mm_broadband_modem_xmm7360_rpc_sequence_full (MMBroadbandModemXmm7360 *self,
+ MMPortSerialXmmrpcXmm7360 *port,
+ const MMBroadbandModemXmm7360RpcCommand *sequence,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GCancellable *modem_cancellable;
+ GTask *task;
+
+ modem_cancellable = mm_base_modem_peek_cancellable (MM_BASE_MODEM (self));
+ task = g_task_new (self,
+ cancellable ? cancellable : modem_cancellable,
+ callback,
+ user_data);
+
+ rpc_sequence_common (self,
+ port,
+ sequence,
+ task,
+ cancellable ? modem_cancellable : NULL);
+}
+
+Xmm7360RpcResponse *
+mm_broadband_modem_xmm7360_rpc_sequence_finish (MMBroadbandModemXmm7360 *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return mm_broadband_modem_xmm7360_rpc_sequence_full_finish (self, res, error);
+}
+
+void
+mm_broadband_modem_xmm7360_rpc_sequence (MMBroadbandModemXmm7360 *self,
+ const MMBroadbandModemXmm7360RpcCommand *sequence,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMPortSerialXmmrpcXmm7360 *port;
+ GError *error = NULL;
+ GTask *task;
+
+ task = g_task_new (self,
+ mm_base_modem_peek_cancellable (MM_BASE_MODEM (self)),
+ callback,
+ user_data);
+
+ /* No port given, so we'll try to guess which is best */
+ port = mm_broadband_modem_xmm7360_peek_port_xmmrpc (self);
+ if (!port) {
+ g_set_error (&error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_CONNECTED,
+ "No XMMRPC port available to run command");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ rpc_sequence_common (self,
+ port,
+ sequence,
+ task,
+ NULL);
+}
+
+/*****************************************************************************/
+/* Response processor helpers */
+
+MMBroadbandModemXmm7360RpcResponseProcessorResult
+mm_broadband_modem_xmm7360_rpc_response_processor_final (MMBroadbandModemXmm7360 *self,
+ Xmm7360RpcResponse *response,
+ gboolean last_command,
+ const GError *error,
+ GError **result_error)
+{
+ if (error) {
+ *result_error = g_error_copy (error);
+ return MM_BROADBAND_MODEM_XMM7360_RPC_RESPONSE_PROCESSOR_RESULT_FAILURE;
+ }
+
+ *result_error = NULL;
+ return MM_BROADBAND_MODEM_XMM7360_RPC_RESPONSE_PROCESSOR_RESULT_SUCCESS;
+}
+
+MMBroadbandModemXmm7360RpcResponseProcessorResult
+mm_broadband_modem_xmm7360_rpc_response_processor_continue_on_success (MMBroadbandModemXmm7360 *self,
+ Xmm7360RpcResponse *response,
+ gboolean last_command,
+ const GError *error,
+ GError **result_error)
+{
+ if (error) {
+ *result_error = g_error_copy (error);
+ return MM_BROADBAND_MODEM_XMM7360_RPC_RESPONSE_PROCESSOR_RESULT_FAILURE;
+ }
+
+ *result_error = NULL;
+ return MM_BROADBAND_MODEM_XMM7360_RPC_RESPONSE_PROCESSOR_RESULT_CONTINUE;
+}
+
+MMBroadbandModemXmm7360RpcResponseProcessorResult
+mm_broadband_modem_xmm7360_rpc_response_processor_continue_on_error (MMBroadbandModemXmm7360 *self,
+ Xmm7360RpcResponse *response,
+ gboolean last_command,
+ const GError *error,
+ GError **result_error)
+{
+ *result_error = NULL;
+ return (error ?
+ MM_BROADBAND_MODEM_XMM7360_RPC_RESPONSE_PROCESSOR_RESULT_CONTINUE :
+ MM_BROADBAND_MODEM_XMM7360_RPC_RESPONSE_PROCESSOR_RESULT_SUCCESS);
+}
+
+/*****************************************************************************/
+/* Single RPC command handling */
+
+typedef struct {
+ MMPortSerialXmmrpcXmm7360 *port;
+ gulong cancelled_id;
+ GCancellable *parent_cancellable;
+} RpcCommandContext;
+
+static void
+rpc_command_context_free (RpcCommandContext *ctx)
+{
+ mm_port_serial_close (MM_PORT_SERIAL (ctx->port));
+
+ if (ctx->parent_cancellable) {
+ g_cancellable_disconnect (ctx->parent_cancellable,
+ ctx->cancelled_id);
+ g_object_unref (ctx->parent_cancellable);
+ }
+
+ g_object_unref (ctx->port);
+ g_free (ctx);
+}
+
+Xmm7360RpcResponse *
+mm_broadband_modem_xmm7360_rpc_command_full_finish (MMBroadbandModemXmm7360 *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_pointer (G_TASK (res), error);
+}
+
+static void
+rpc_command_ready (MMPortSerialXmmrpcXmm7360 *port,
+ GAsyncResult *res,
+ GTask *task)
+{
+ g_autoptr(GError) command_error = NULL;
+ Xmm7360RpcResponse *response;
+
+ response = mm_port_serial_xmmrpc_xmm7360_command_finish (port, res, &command_error);
+
+ if (g_task_return_error_if_cancelled (task)) {
+ /* task cancelled */
+ g_object_unref (task);
+ return;
+ }
+
+ if (command_error)
+ /* error coming from the serial port */
+ g_task_return_error (task, g_steal_pointer (&command_error));
+ else if (response)
+ /* valid response */
+ g_task_return_pointer (task, response, (GDestroyNotify)xmm7360_rpc_response_free);
+ else
+ g_assert_not_reached ();
+ g_object_unref (task);
+}
+
+static void
+rpc_command_common (MMBroadbandModemXmm7360 *self,
+ MMPortSerialXmmrpcXmm7360 *port,
+ Xmm7360RpcCallId callid,
+ gboolean is_async,
+ GByteArray *body,
+ guint timeout,
+ gboolean allow_cached,
+ GTask *task,
+ GCancellable *parent_cancellable)
+{
+ RpcCommandContext *ctx;
+
+ /* Ensure that we have an open port */
+ if (!abort_task_if_port_unusable (self, port, task))
+ return;
+
+ ctx = g_new0 (RpcCommandContext, 1);
+ ctx->port = g_object_ref (port);
+
+ /* Ensure the cancellable that's already associated with the modem
+ * will also get cancelled if the modem wide-one gets cancelled */
+ if (parent_cancellable) {
+ GCancellable *cancellable;
+
+ cancellable = g_task_get_cancellable (task);
+ ctx->parent_cancellable = g_object_ref (parent_cancellable);
+ ctx->cancelled_id = g_cancellable_connect (ctx->parent_cancellable,
+ G_CALLBACK (parent_cancellable_cancelled),
+ cancellable,
+ NULL);
+ }
+
+ g_task_set_task_data (task, ctx, (GDestroyNotify)rpc_command_context_free);
+
+ /* Go on with the command */
+ mm_port_serial_xmmrpc_xmm7360_command (
+ port,
+ callid,
+ is_async,
+ body,
+ timeout,
+ allow_cached,
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback)rpc_command_ready,
+ task);
+}
+
+void
+mm_broadband_modem_xmm7360_rpc_command_full (MMBroadbandModemXmm7360 *self,
+ MMPortSerialXmmrpcXmm7360 *port,
+ Xmm7360RpcCallId callid,
+ gboolean is_async,
+ GByteArray *body,
+ guint timeout,
+ gboolean allow_cached,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GCancellable *modem_cancellable;
+ GTask *task;
+
+ modem_cancellable = mm_base_modem_peek_cancellable (MM_BASE_MODEM (self));
+ task = g_task_new (self,
+ cancellable ? cancellable : modem_cancellable,
+ callback,
+ user_data);
+
+ rpc_command_common (self,
+ port,
+ callid,
+ is_async,
+ body,
+ timeout,
+ allow_cached,
+ task,
+ cancellable ? modem_cancellable : NULL);
+}
+
+Xmm7360RpcResponse *
+mm_broadband_modem_xmm7360_rpc_command_finish (MMBroadbandModemXmm7360 *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return mm_broadband_modem_xmm7360_rpc_command_full_finish (self, res, error);
+}
+
+static void
+_rpc_command (MMBroadbandModemXmm7360 *self,
+ Xmm7360RpcCallId callid,
+ gboolean is_async,
+ GByteArray *body,
+ guint timeout,
+ gboolean allow_cached,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMPortSerialXmmrpcXmm7360 *port;
+ GError *error = NULL;
+ GTask *task;
+
+ task = g_task_new (self,
+ mm_base_modem_peek_cancellable (MM_BASE_MODEM (self)),
+ callback,
+ user_data);
+
+ /* No port given, so we'll try to guess which is best */
+ port = mm_broadband_modem_xmm7360_peek_port_xmmrpc (self);
+ if (!port) {
+ g_set_error (&error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_CONNECTED,
+ "No XMMRPC port available to run command");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ rpc_command_common (self,
+ port,
+ callid,
+ is_async,
+ body,
+ timeout,
+ allow_cached,
+ task,
+ NULL);
+}
+
+void
+mm_broadband_modem_xmm7360_rpc_command (MMBroadbandModemXmm7360 *self,
+ Xmm7360RpcCallId callid,
+ gboolean is_async,
+ GByteArray *body,
+ guint timeout,
+ gboolean allow_cached,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ _rpc_command (self, callid, is_async, body, timeout, allow_cached, callback, user_data);
+}
diff --git a/src/plugins/intel/mm-broadband-modem-xmm7360-rpc.h b/src/plugins/intel/mm-broadband-modem-xmm7360-rpc.h
new file mode 100644
index 00000000..18d107bc
--- /dev/null
+++ b/src/plugins/intel/mm-broadband-modem-xmm7360-rpc.h
@@ -0,0 +1,173 @@
+/* -*- 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 Thomas Vogt
+ */
+
+#ifndef MM_BROADBAND_MODEM_XMM7360_RPC_H
+#define MM_BROADBAND_MODEM_XMM7360_RPC_H
+
+#include <gio/gio.h>
+
+#include "mm-broadband-modem-xmm7360.h"
+#include "mm-port-serial-xmmrpc-xmm7360.h"
+
+typedef enum {
+ MM_BROADBAND_MODEM_XMM7360_RPC_RESPONSE_PROCESSOR_RESULT_CONTINUE,
+ MM_BROADBAND_MODEM_XMM7360_RPC_RESPONSE_PROCESSOR_RESULT_SUCCESS,
+ MM_BROADBAND_MODEM_XMM7360_RPC_RESPONSE_PROCESSOR_RESULT_FAILURE,
+} MMBroadbandModemXmm7360RpcResponseProcessorResult;
+
+/*
+ * SUCCESS must be returned when the operation is to be considered successful,
+ * and a result may be given.
+ *
+ * FAILURE must be returned when a GError is propagated into result_error,
+ * which will be treated as a critical error and therefore the operation will be aborted.
+ *
+ * CONTINUE must be returned when no result_error is given and
+ * the operation should go on with the next scheduled command.
+ *
+ * This setup, therefore allows:
+ * - Running a single command and processing its result.
+ * - Running a set of N commands out of M (N<M), where the global result is
+ * obtained without having executed all configured commands.
+ */
+typedef MMBroadbandModemXmm7360RpcResponseProcessorResult (* MMBroadbandModemXmm7360RpcResponseProcessor) (
+ MMBroadbandModemXmm7360 *self,
+ Xmm7360RpcResponse *response,
+ gboolean last_command,
+ const GError *error,
+ GError **result_error);
+
+/* Struct to configure XMMRPC command operations */
+typedef struct {
+ /* The RCP command's call ID */
+ Xmm7360RpcCallId callid;
+ /* Async or sync type RCP command */
+ gboolean is_async;
+ /* payload */
+ const Xmm7360RpcMsgArg *body;
+ /* Timeout of the command, in seconds */
+ guint timeout;
+ /* Flag to allow cached replies */
+ gboolean allow_cached;
+ /* The response processor */
+ MMBroadbandModemXmm7360RpcResponseProcessor response_processor;
+ /* Time to wait before sending this command (in seconds) */
+ guint wait_seconds;
+} MMBroadbandModemXmm7360RpcCommand;
+
+/* Generic RPC sequence handling, using the first XMMRPC port available and without
+ * explicit cancellations. */
+void mm_broadband_modem_xmm7360_rpc_sequence (
+ MMBroadbandModemXmm7360 *self,
+ const MMBroadbandModemXmm7360RpcCommand *sequence,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+Xmm7360RpcResponse *mm_broadband_modem_xmm7360_rpc_sequence_finish (
+ MMBroadbandModemXmm7360 *self,
+ GAsyncResult *res,
+ GError **error);
+
+/* Fully detailed RPC sequence handling, when specific XMMRPC port and/or explicit
+ * cancellations need to be used. */
+void mm_broadband_modem_xmm7360_rpc_sequence_full (
+ MMBroadbandModemXmm7360 *self,
+ MMPortSerialXmmrpcXmm7360 *port,
+ const MMBroadbandModemXmm7360RpcCommand *sequence,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+Xmm7360RpcResponse *mm_broadband_modem_xmm7360_rpc_sequence_full_finish (
+ MMBroadbandModemXmm7360 *self,
+ GAsyncResult *res,
+ GError **error);
+
+/* Common helper response processors */
+
+/*
+ * Response processor for commands that are treated as MANDATORY, where a
+ * failure in the command triggers a failure in the sequence.
+ */
+MMBroadbandModemXmm7360RpcResponseProcessorResult mm_broadband_modem_xmm7360_rpc_response_processor_final (
+ MMBroadbandModemXmm7360 *self,
+ Xmm7360RpcResponse *response,
+ gboolean last_command,
+ const GError *error,
+ GError **result_error);
+
+/*
+ * Response processor for commands that are treated as MANDATORY, where a
+ * failure in the command triggers a failure in the sequence. If successful,
+ * it will run the next command in the sequence.
+ *
+ * E.g. used when we provide a list of commands and we want to run all of
+ * them successfully, and fail the sequence if one of them fails.
+ */
+MMBroadbandModemXmm7360RpcResponseProcessorResult mm_broadband_modem_xmm7360_rpc_response_processor_continue_on_success (
+ MMBroadbandModemXmm7360 *self,
+ Xmm7360RpcResponse *response,
+ gboolean last_command,
+ const GError *error,
+ GError **result_error);
+
+/*
+ * Response processor for commands that are treated as OPTIONAL, where a
+ * failure in the command doesn't trigger a failure in the sequence. If
+ * successful, it finishes the sequence.
+ *
+ * E.g. used when we provide a list of commands and we want to stop
+ * as soon as one of them doesn't fail.
+ */
+MMBroadbandModemXmm7360RpcResponseProcessorResult mm_broadband_modem_xmm7360_rpc_response_processor_continue_on_error (
+ MMBroadbandModemXmm7360 *self,
+ Xmm7360RpcResponse *response,
+ gboolean last_command,
+ const GError *error,
+ GError **result_error);
+
+/* Generic RPC command handling, using the best XMMRPC port available and without
+ * explicit cancellations. */
+void mm_broadband_modem_xmm7360_rpc_command (
+ MMBroadbandModemXmm7360 *self,
+ Xmm7360RpcCallId callid,
+ gboolean is_async,
+ GByteArray *body,
+ guint timeout,
+ gboolean allow_cached,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+Xmm7360RpcResponse *mm_broadband_modem_xmm7360_rpc_command_finish (
+ MMBroadbandModemXmm7360 *self,
+ GAsyncResult *res,
+ GError **error);
+
+/* Fully detailed RPC command handling, when specific XMMRPC port and/or explicit
+ * cancellations need to be used. */
+void mm_broadband_modem_xmm7360_rpc_command_full (
+ MMBroadbandModemXmm7360 *self,
+ MMPortSerialXmmrpcXmm7360 *port,
+ Xmm7360RpcCallId callid,
+ gboolean is_async,
+ GByteArray *body,
+ guint timeout,
+ gboolean allow_cached,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+Xmm7360RpcResponse *mm_broadband_modem_xmm7360_rpc_command_full_finish (
+ MMBroadbandModemXmm7360 *self,
+ GAsyncResult *res,
+ GError **error);
+
+#endif /* MM_BROADBAND_MODEM_XMM7360_RPC_H */
diff --git a/src/plugins/intel/mm-broadband-modem-xmm7360.c b/src/plugins/intel/mm-broadband-modem-xmm7360.c
new file mode 100644
index 00000000..a4357079
--- /dev/null
+++ b/src/plugins/intel/mm-broadband-modem-xmm7360.c
@@ -0,0 +1,1229 @@
+/* -*- 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) 2019 James Wah
+ * Copyright (C) 2020 Marinus Enzinger <marinus@enzingerm.de>
+ * Copyright (C) 2023 Shane Parslow
+ * Copyright (C) 2024 Thomas Vogt
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include <ModemManager.h>
+#define _LIBMM_INSIDE_MM
+#include <libmm-glib.h>
+
+#include "mm-log-object.h"
+#include "mm-iface-modem.h"
+#include "mm-iface-modem-3gpp.h"
+#include "mm-iface-modem-location.h"
+#include "mm-broadband-modem-xmm.h"
+
+#include "mm-broadband-modem-xmm7360.h"
+#include "mm-broadband-modem-xmm7360-rpc.h"
+#include "mm-port-serial-xmmrpc-xmm7360.h"
+#include "mm-bearer-xmm7360.h"
+#include "mm-sim-xmm7360.h"
+
+static void iface_modem_init (MMIfaceModemInterface *iface);
+static void iface_modem_3gpp_init (MMIfaceModem3gppInterface *iface);
+static void iface_modem_location_init (MMIfaceModemLocationInterface *iface);
+
+static MMIfaceModemInterface *iface_modem_parent;
+
+G_DEFINE_TYPE_EXTENDED (MMBroadbandModemXmm7360, mm_broadband_modem_xmm7360, MM_TYPE_BROADBAND_MODEM_XMM, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
+)
+
+struct _MMBroadbandModemXmm7360Private {
+ MMUnlockRetries *unlock_retries;
+};
+
+/*****************************************************************************/
+/* Create Bearer (Modem interface) */
+
+static void
+create_bearer (MMIfaceModem *self,
+ MMBearerProperties *properties,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMBaseBearer *bearer;
+ GTask *task;
+
+ bearer = mm_bearer_xmm7360_new (MM_BROADBAND_MODEM_XMM7360 (self), properties);
+
+ task = g_task_new (self, NULL, callback, user_data);
+ g_task_return_pointer (task, bearer, (GDestroyNotify)g_object_unref);
+ g_object_unref (task);
+}
+
+static MMBaseBearer *
+create_bearer_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_pointer (G_TASK (res), error);
+}
+
+/*****************************************************************************/
+/* Create SIM (Modem interface) */
+
+static MMBaseSim *
+create_sim_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return mm_sim_xmm7360_new_finish (res, error);
+}
+
+static void
+create_sim (MMIfaceModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ /* New XMM7360 SIM */
+ mm_sim_xmm7360_new (MM_BASE_MODEM (self),
+ NULL, /* cancellable */
+ callback,
+ user_data);
+}
+
+/*****************************************************************************/
+/* Set initial EPS bearer settings (3GPP interface) */
+
+typedef enum {
+ APN_AUTH_TYPE_NONE = 0,
+ APN_AUTH_TYPE_PAP = 1,
+ APN_AUTH_TYPE_CHAP = 2,
+} ApnAuthType;
+
+static gboolean
+modem_3gpp_set_initial_eps_bearer_settings_finish (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+attach_apn_config_ready (MMBroadbandModemXmm7360 *modem,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (modem, res, &error);
+ if (error) {
+ g_task_return_error (task, error);
+ } else {
+ g_task_return_boolean (task, TRUE);
+ }
+ g_object_unref (task);
+
+
+}
+
+static GByteArray *
+padded_pack_uta_ms_call_ps_attach_apn_config_req (const gchar *apn_padded,
+ ApnAuthType auth_type,
+ const gchar *user_padded,
+ const gchar *password_padded)
+{
+ static const gchar zeroes[270] = { 0 };
+ const Xmm7360RpcMsgArg args[] = {
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 257, 3 },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 65, 1 },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 65, 0 },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 250, 0 },
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 250, 2 },
+ { XMM7360_RPC_MSG_ARG_TYPE_SHORT, { .s = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 20, 0 },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 101, 3 },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 257, 3 },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 65, 1 },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 65, 0 },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 250, 0 },
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 250, 2 },
+ { XMM7360_RPC_MSG_ARG_TYPE_SHORT, { .s = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 20, 0 },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 101, 3 },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 257, 3 },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = auth_type } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = password_padded }, 65, 1 },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = user_padded }, 65, 0 },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 250, 0 },
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 250, 2 },
+ { XMM7360_RPC_MSG_ARG_TYPE_SHORT, { .s = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 1 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 1 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0x404 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 1 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 1 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 20, 0 },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 3 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = apn_padded }, 101, 3 },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 257, 3 },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = auth_type } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = password_padded }, 65, 1 },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = user_padded }, 65, 0 },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 250, 0 },
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 250, 2 },
+ { XMM7360_RPC_MSG_ARG_TYPE_SHORT, { .s = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 1 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 1 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0x404 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 1 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 1 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = zeroes }, 20, 0 },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 3 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = apn_padded }, 101, 2 },
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 3 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN },
+ };
+ return xmm7360_rpc_args_to_byte_array (args);
+}
+
+static GByteArray *
+pack_uta_ms_call_ps_attach_apn_config_req (const gchar *apn,
+ MMBearerAllowedAuth allowed_auth,
+ const gchar *user,
+ const gchar *password)
+{
+ gchar apn_padded[102] = { 0 };
+ gchar user_padded[66] = { 0 };
+ gchar password_padded[66] = { 0 };
+ ApnAuthType auth_type;
+
+ if (apn != NULL)
+ g_strlcpy (apn_padded, apn, sizeof (apn_padded));
+ if (user != NULL)
+ g_strlcpy (user_padded, user, sizeof (user_padded));
+ if (password != NULL)
+ g_strlcpy (password_padded, password, sizeof (password_padded));
+
+ if (allowed_auth & MM_BEARER_ALLOWED_AUTH_NONE) {
+ auth_type = APN_AUTH_TYPE_NONE;
+ } else if (allowed_auth & MM_BEARER_ALLOWED_AUTH_PAP) {
+ auth_type = APN_AUTH_TYPE_PAP;
+ } else if (allowed_auth & MM_BEARER_ALLOWED_AUTH_CHAP) {
+ auth_type = APN_AUTH_TYPE_CHAP;
+ } else {
+ gchar *str;
+
+ str = mm_bearer_allowed_auth_build_string_from_mask (allowed_auth);
+ mm_obj_dbg (NULL,
+ "Specified APN authentication methods unknown (%s)."
+ " Falling back to default method (none).",
+ str);
+ auth_type = APN_AUTH_TYPE_NONE;
+ g_free (str);
+ }
+
+ return padded_pack_uta_ms_call_ps_attach_apn_config_req (apn_padded,
+ auth_type,
+ user_padded,
+ password_padded);
+}
+
+static void
+modem_3gpp_set_initial_eps_bearer_settings (MMIfaceModem3gpp *_self,
+ MMBearerProperties *config,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMBroadbandModemXmm7360 *self = MM_BROADBAND_MODEM_XMM7360 (_self);
+ g_autoptr(MMPortSerialXmmrpcXmm7360) port = NULL;
+ GTask *task;
+ g_autoptr(GByteArray) body = NULL;
+
+ port = mm_broadband_modem_xmm7360_get_port_xmmrpc (self);
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ body = pack_uta_ms_call_ps_attach_apn_config_req (mm_bearer_properties_get_apn (config),
+ mm_bearer_properties_get_allowed_auth (config),
+ mm_bearer_properties_get_user (config),
+ mm_bearer_properties_get_password (config));
+
+ mm_broadband_modem_xmm7360_rpc_command_full (self,
+ port,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_ATTACH_APN_CONFIG_REQ,
+ TRUE,
+ body,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)attach_apn_config_ready,
+ task);
+}
+
+/*****************************************************************************/
+
+MMPortSerialXmmrpcXmm7360 *
+mm_broadband_modem_xmm7360_peek_port_xmmrpc (MMBroadbandModemXmm7360 *self)
+{
+ MMPortSerialXmmrpcXmm7360 *primary_xmmrpc_port = NULL;
+ GList *xmmrpc_ports;
+
+ g_assert (MM_IS_BROADBAND_MODEM_XMM7360 (self));
+
+ xmmrpc_ports = mm_base_modem_find_ports (MM_BASE_MODEM (self),
+ MM_PORT_SUBSYS_UNKNOWN,
+ MM_PORT_TYPE_XMMRPC);
+
+ /* First XMMRPC port in the list is the primary one always */
+ if (xmmrpc_ports) {
+ primary_xmmrpc_port = mm_port_serial_xmmrpc_xmm7360_new (
+ mm_port_get_device (MM_PORT (xmmrpc_ports->data))
+ );
+ }
+
+ g_list_free_full (xmmrpc_ports, g_object_unref);
+
+ return primary_xmmrpc_port;
+}
+
+MMPortSerialXmmrpcXmm7360 *
+mm_broadband_modem_xmm7360_get_port_xmmrpc (MMBroadbandModemXmm7360 *self)
+{
+ MMPortSerialXmmrpcXmm7360 *primary_xmmrpc_port;
+
+ g_assert (MM_IS_BROADBAND_MODEM_XMM7360 (self));
+
+ primary_xmmrpc_port = mm_broadband_modem_xmm7360_peek_port_xmmrpc (self);
+ return (primary_xmmrpc_port ?
+ MM_PORT_SERIAL_XMMRPC_XMM7360 (g_object_ref (primary_xmmrpc_port)) :
+ NULL);
+}
+
+/*****************************************************************************/
+
+void
+mm_broadband_modem_xmm7360_set_unlock_retries (MMBroadbandModemXmm7360 *self,
+ MMModemLock lock_type,
+ guint32 remaining_attempts)
+{
+ g_assert (MM_IS_BROADBAND_MODEM_XMM7360 (self));
+
+ if (!self->priv->unlock_retries)
+ self->priv->unlock_retries = mm_unlock_retries_new ();
+
+ /* Interpret 0xffffffff as device not supporting this information. */
+ if (remaining_attempts != G_MAXUINT32)
+ mm_unlock_retries_set (self->priv->unlock_retries,
+ lock_type,
+ remaining_attempts);
+}
+
+/*****************************************************************************/
+
+typedef struct {
+ MMPortSerialXmmrpcXmm7360 *port;
+ gboolean port_dispose;
+ gboolean unlock;
+} CheckFccLockContext;
+
+static void
+check_fcc_lock_context_free (CheckFccLockContext *ctx)
+{
+ if (ctx->port_dispose) {
+ mm_port_serial_close (MM_PORT_SERIAL (ctx->port));
+ g_clear_object (&ctx->port);
+ }
+ g_slice_free (CheckFccLockContext, ctx);
+}
+
+gboolean
+mm_broadband_modem_xmm7360_check_fcc_lock_finish (MMBroadbandModemXmm7360 *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+fcc_unlock_ready (MMBroadbandModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+ Xmm7360RpcMsgArg *arg;
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (MM_BROADBAND_MODEM_XMM7360 (self),
+ res,
+ &error);
+
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (response->content->len < 1) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Invalid response after answering FCC unlock challenge (too short)");
+ g_object_unref (task);
+ return;
+ }
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 0);
+ g_assert (arg->type == XMM7360_RPC_MSG_ARG_TYPE_LONG);
+ if (XMM7360_RPC_MSG_ARG_GET_INT (arg) != 1) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Our answer to the FCC unlock challenge was not accepted");
+ g_object_unref (task);
+ return;
+ }
+
+ /* successfully unlocked, return FALSE (unlock not required) */
+ g_task_return_boolean (task, FALSE);
+ g_object_unref (task);
+}
+
+static void
+fcc_unlock_challenge_ready (MMBroadbandModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ CheckFccLockContext *ctx;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+ Xmm7360RpcMsgArg *arg;
+ gint32 fcc_challenge;
+ GChecksum *checksum;
+ guchar salt[] = { 0x3d, 0xf8, 0xc7, 0x19 };
+ guint8 digest[32] = { 0 };
+ gsize digest_len = 32;
+ g_autoptr(GByteArray) digest_response = NULL;
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (MM_BROADBAND_MODEM_XMM7360 (self),
+ res,
+ &error);
+
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 1);
+ g_assert (arg->type == XMM7360_RPC_MSG_ARG_TYPE_LONG);
+ fcc_challenge = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ checksum = g_checksum_new (G_CHECKSUM_SHA256);
+ g_checksum_update (checksum, (guchar *) &fcc_challenge, 4);
+ g_checksum_update (checksum, salt, 4);
+ g_checksum_get_digest (checksum, digest, &digest_len);
+ g_checksum_free (checksum);
+
+ digest_response = g_byte_array_new ();
+ xmm7360_byte_array_append_asn_int4 (digest_response, GINT32_FROM_LE (*(gint32 *) digest));
+
+ ctx = g_task_get_task_data (task);
+ mm_broadband_modem_xmm7360_rpc_command_full (MM_BROADBAND_MODEM_XMM7360 (self),
+ ctx->port,
+ XMM7360_RPC_CALL_CSI_FCC_LOCK_VER_CHALLENGE_REQ,
+ TRUE,
+ digest_response,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)fcc_unlock_ready,
+ task);
+}
+
+static void
+fcc_lock_query_ready (MMBroadbandModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ CheckFccLockContext *ctx;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+ Xmm7360RpcMsgArg *arg;
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (MM_BROADBAND_MODEM_XMM7360 (self),
+ res,
+ &error);
+
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (response->content->len < 2) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "The response to the FCC check is invalid (too short)");
+ g_object_unref (task);
+ return;
+ }
+
+ /* second argument is fcc_state */
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 1);
+ g_assert (arg->type == XMM7360_RPC_MSG_ARG_TYPE_LONG);
+ if (XMM7360_RPC_MSG_ARG_GET_INT (arg)) {
+ /* no FCC unlock required: FCC state is != 0 */
+ g_task_return_boolean (task, FALSE);
+ g_object_unref (task);
+ return;
+ }
+
+ /* third argument is fcc_mode */
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 2);
+ g_assert (arg->type == XMM7360_RPC_MSG_ARG_TYPE_LONG);
+ if (!XMM7360_RPC_MSG_ARG_GET_INT (arg)) {
+ /* no FCC unlock required: FCC mode is == 0 */
+ g_task_return_boolean (task, FALSE);
+ g_object_unref (task);
+ return;
+ }
+
+ /* FCC unlock required: FCC mode is != 0 */
+ ctx = g_task_get_task_data (task);
+
+ if (!ctx->unlock) {
+ /* we are told not to unlock, return TRUE (unlock required) */
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+
+ /* request unlock challenge */
+ mm_broadband_modem_xmm7360_rpc_command_full (MM_BROADBAND_MODEM_XMM7360 (self),
+ ctx->port,
+ XMM7360_RPC_CALL_CSI_FCC_LOCK_GEN_CHALLENGE_REQ,
+ TRUE,
+ NULL, /* body */
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)fcc_unlock_challenge_ready,
+ task);
+}
+
+void
+mm_broadband_modem_xmm7360_check_fcc_lock (MMBroadbandModemXmm7360 *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ MMPortSerialXmmrpcXmm7360 *port,
+ gboolean unlock)
+{
+ GError *error = NULL;
+ CheckFccLockContext *ctx;
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ ctx = g_slice_new0 (CheckFccLockContext);
+ ctx->port = port;
+ ctx->port_dispose = FALSE;
+ ctx->unlock = unlock;
+ g_task_set_task_data (task, ctx, (GDestroyNotify)check_fcc_lock_context_free);
+
+ if (!port) {
+ /* if no port is given, open a new XMMRPC port for the FCC lock query */
+ ctx->port = mm_broadband_modem_xmm7360_get_port_xmmrpc (self);
+ ctx->port_dispose = TRUE;
+
+ if (!mm_port_serial_open (MM_PORT_SERIAL (ctx->port), &error)) {
+ g_prefix_error (&error, "Couldn't open XMMRPC port during FCC lock query: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+ }
+
+ mm_broadband_modem_xmm7360_rpc_command_full (MM_BROADBAND_MODEM_XMM7360 (self),
+ ctx->port,
+ XMM7360_RPC_CALL_CSI_FCC_LOCK_QUERY_REQ,
+ TRUE,
+ NULL, /* body */
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)fcc_lock_query_ready,
+ task);
+}
+
+/*****************************************************************************/
+
+typedef struct {
+ MMPortSerialXmmrpcXmm7360 *port;
+ guint unsol_handler_id;
+ guint timeout_id;
+ gboolean is_fcc_unlocked;
+ gboolean is_uta_mode_set;
+ gboolean is_sim_initialized;
+ gboolean awaiting_uta_mode_set_rsp_cb;
+} PowerUpContext;
+
+static void
+power_up_context_free (PowerUpContext *ctx)
+{
+ if (ctx->timeout_id)
+ g_source_remove (ctx->timeout_id);
+ if (ctx->unsol_handler_id)
+ mm_port_serial_xmmrpc_xmm7360_enable_unsolicited_msg_handler (
+ ctx->port,
+ ctx->unsol_handler_id,
+ FALSE);
+ mm_port_serial_close (MM_PORT_SERIAL (ctx->port));
+ g_clear_object (&ctx->port);
+ g_slice_free (PowerUpContext, ctx);
+}
+
+static gboolean
+modem_power_up_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+parent_modem_power_up_ready (MMIfaceModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ gboolean parent_res;
+ GError *error = NULL;
+
+ parent_res = iface_modem_parent->modem_power_up_finish (self, res, &error);
+
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ /* parent's result passed here */
+ g_task_return_boolean (task, parent_res);
+ g_object_unref (task);
+}
+
+static void
+modem_power_up_ready (MMIfaceModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ gboolean success;
+
+ success = g_task_propagate_boolean (G_TASK (res), &error);
+ if (error || !success) {
+ if (error) {
+ g_task_return_error (task, error);
+ } else {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Powering up XMM7360 failed (unknown reason)");
+ }
+ g_object_unref (task);
+ return;
+ }
+
+ iface_modem_parent->modem_power_up (
+ self,
+ (GAsyncReadyCallback)parent_modem_power_up_ready,
+ task);
+}
+
+static gboolean
+power_up_timeout_cb (GTask *task)
+{
+ MMBroadbandModemXmm7360 *self;
+ PowerUpContext *ctx;
+
+ ctx = g_task_get_task_data (task);
+ self = g_task_get_source_object (task);
+
+ if (ctx->is_uta_mode_set) {
+ if (!ctx->is_sim_initialized) {
+ /* this can happen if the device was initialized before */
+ mm_obj_warn (self, "Waiting for SIM init timed out (trying to continue anyway...)");
+ g_task_return_boolean (task, TRUE);
+ }
+ } else {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Initialization timed out (waiting for UTA mode)");
+ }
+ g_object_unref (task);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+uta_mode_set_ready (MMBroadbandModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ PowerUpContext *ctx;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (MM_BROADBAND_MODEM_XMM7360 (self),
+ res,
+ &error);
+
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (response->content->len < 1) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Invalid response setting UTA mode (too short)");
+ g_object_unref (task);
+ return;
+ }
+
+ ctx = g_task_get_task_data (task);
+ ctx->awaiting_uta_mode_set_rsp_cb = TRUE;
+ ctx->timeout_id = g_timeout_add_seconds (5, (GSourceFunc)power_up_timeout_cb, task);
+}
+
+static GByteArray *
+pack_uta_mode_set (gint32 mode)
+{
+ const Xmm7360RpcMsgArg args[] = {
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 15 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = mode } },
+ { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN },
+ };
+ return xmm7360_rpc_args_to_byte_array (args);
+}
+
+static void
+check_fcc_lock_ready (MMBroadbandModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ gboolean locked;
+ PowerUpContext *ctx;
+ g_autoptr(GByteArray) body = NULL;
+
+ locked = mm_broadband_modem_xmm7360_check_fcc_lock_finish (MM_BROADBAND_MODEM_XMM7360 (self),
+ res,
+ &error);
+
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (locked) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_RETRY,
+ "Modem is FCC locked.");
+ g_object_unref (task);
+ return;
+ }
+
+ ctx = g_task_get_task_data (task);
+ ctx->is_fcc_unlocked = TRUE;
+
+ body = pack_uta_mode_set (1);
+
+ mm_broadband_modem_xmm7360_rpc_command_full (MM_BROADBAND_MODEM_XMM7360 (self),
+ ctx->port,
+ XMM7360_RPC_CALL_UTA_MODE_SET_REQ,
+ FALSE,
+ body,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)uta_mode_set_ready,
+ task);
+}
+
+static gboolean
+power_up_unsol_handler (MMPortSerialXmmrpcXmm7360 *port,
+ Xmm7360RpcResponse *response,
+ GTask *task)
+{
+ PowerUpContext *ctx;
+ Xmm7360RpcMsgArg *arg;
+ gint32 value;
+
+ ctx = g_task_get_task_data (task);
+
+ if (response->unsol_id == XMM7360_RPC_UNSOL_UTA_MS_SIM_INIT_IND_CB) {
+ ctx->is_sim_initialized = TRUE;
+ } else if (response->unsol_id == XMM7360_RPC_UNSOL_UTA_MODE_SET_RSP_CB) {
+ if (!ctx->awaiting_uta_mode_set_rsp_cb) {
+ mm_obj_dbg (port, "Ignoring premature MODE_SET_RSP_CB ...");
+ return TRUE;
+ }
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 0);
+
+ if (arg->type != XMM7360_RPC_MSG_ARG_TYPE_LONG) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "The response to the UTA mode-set is invalid (wrong type)");
+ g_object_unref (task);
+ return TRUE;
+ }
+
+ value = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+ if (value != 1) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Setting UTA mode failed (wrong value: %d)", value);
+ g_object_unref (task);
+ return TRUE;
+ }
+
+ ctx->is_uta_mode_set = TRUE;
+ } else {
+ return FALSE;
+ }
+
+ /* we check each time since the two messages might come in any order */
+ if (ctx->awaiting_uta_mode_set_rsp_cb && ctx->is_uta_mode_set && ctx->is_sim_initialized) {
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ }
+
+ return TRUE;
+}
+
+static void
+modem_power_up (MMIfaceModem *iface,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ MMBroadbandModemXmm7360 *self = MM_BROADBAND_MODEM_XMM7360 (iface);
+ PowerUpContext *ctx;
+ GTask *task;
+
+ task = g_task_new (self,
+ NULL,
+ (GAsyncReadyCallback)modem_power_up_ready,
+ g_task_new (self, NULL, callback, user_data));
+
+ ctx = g_slice_new0 (PowerUpContext);
+ ctx->port = mm_broadband_modem_xmm7360_get_port_xmmrpc (self);
+ ctx->is_fcc_unlocked = FALSE;
+ ctx->is_uta_mode_set = FALSE;
+ ctx->is_sim_initialized = FALSE;
+ ctx->awaiting_uta_mode_set_rsp_cb = FALSE;
+ ctx->timeout_id = 0;
+ g_task_set_task_data (task, ctx, (GDestroyNotify)power_up_context_free);
+
+ /* Open XMMRPC port for power-up */
+ if (!mm_port_serial_open (MM_PORT_SERIAL (ctx->port), &error)) {
+ g_prefix_error (&error, "Couldn't open XMMRPC port during power-up: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ ctx->unsol_handler_id = mm_port_serial_xmmrpc_xmm7360_add_unsolicited_msg_handler (
+ ctx->port,
+ (MMPortSerialXmmrpcXmm7360UnsolicitedMsgFn)power_up_unsol_handler,
+ task,
+ NULL);
+
+ mm_broadband_modem_xmm7360_check_fcc_lock (MM_BROADBAND_MODEM_XMM7360 (self),
+ (GAsyncReadyCallback)check_fcc_lock_ready,
+ task,
+ ctx->port,
+ FALSE);
+}
+
+/*****************************************************************************/
+
+typedef struct {
+ MMPortSerialXmmrpcXmm7360 *port;
+ guint unsol_handler_id;
+ guint timeout_id;
+ gboolean is_sim_initialized;
+} InitializationStartedContext;
+
+static void
+initialization_started_context_free (InitializationStartedContext *ctx)
+{
+ if (ctx->timeout_id)
+ g_source_remove (ctx->timeout_id);
+ if (ctx->unsol_handler_id)
+ mm_port_serial_xmmrpc_xmm7360_enable_unsolicited_msg_handler (
+ ctx->port,
+ ctx->unsol_handler_id,
+ FALSE);
+ mm_port_serial_close (MM_PORT_SERIAL (ctx->port));
+ g_clear_object (&ctx->port);
+ g_slice_free (InitializationStartedContext, ctx);
+}
+
+static gpointer
+initialization_started_finish (MMBroadbandModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_pointer (G_TASK (res), error);
+}
+
+static void
+parent_initialization_started_ready (MMBroadbandModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ gpointer parent_ctx;
+ GError *error = NULL;
+
+ parent_ctx = MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_xmm7360_parent_class)->initialization_started_finish (
+ self,
+ res,
+ &error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ /* Just parent's pointer passed here */
+ g_task_return_pointer (task, parent_ctx, NULL);
+ g_object_unref (task);
+}
+
+static void
+initialization_started_ready (MMBroadbandModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ gboolean success;
+
+ success = g_task_propagate_boolean (G_TASK (res), &error);
+ if (error || !success) {
+ if (error) {
+ g_task_return_error (task, error);
+ } else {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Initializing XMM7360 failed (unknown reason)");
+ }
+ g_object_unref (task);
+ return;
+ }
+
+ MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_xmm7360_parent_class)->initialization_started (
+ self,
+ (GAsyncReadyCallback)parent_initialization_started_ready,
+ task);
+}
+
+static gboolean
+init_timeout_cb (GTask *task)
+{
+ MMBroadbandModemXmm7360 *self;
+ InitializationStartedContext *ctx;
+
+ ctx = g_task_get_task_data (task);
+ self = g_task_get_source_object (task);
+
+ if (!ctx->is_sim_initialized) {
+ /* this can happen if the device was initialized before */
+ mm_obj_warn (self, "Waiting for SIM init timed out (trying to continue anyway...)");
+ g_task_return_boolean (task, TRUE);
+ }
+
+ g_object_unref (task);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+init_sequence_ready (MMBroadbandModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+ InitializationStartedContext *ctx;
+
+ response = mm_broadband_modem_xmm7360_rpc_sequence_finish (MM_BROADBAND_MODEM_XMM7360 (self),
+ res,
+ &error);
+
+ if (error) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Failed to complete init sequence: %s", error->message);
+ g_object_unref (task);
+ return;
+ }
+
+ ctx = g_task_get_task_data (task);
+ ctx->timeout_id = g_timeout_add_seconds (5, (GSourceFunc)init_timeout_cb, task);
+}
+
+static gboolean
+init_unsol_handler (MMPortSerialXmmrpcXmm7360 *port,
+ Xmm7360RpcResponse *response,
+ GTask *task)
+{
+ InitializationStartedContext *ctx;
+
+ ctx = g_task_get_task_data (task);
+
+ if (response->unsol_id != XMM7360_RPC_UNSOL_UTA_MS_SIM_INIT_IND_CB) {
+ return FALSE;
+ }
+
+ ctx->is_sim_initialized = TRUE;
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return TRUE;
+}
+
+static const Xmm7360RpcMsgArg set_radio_signal_reporting_args[] = {
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 1 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN },
+};
+
+static const MMBroadbandModemXmm7360RpcCommand init_sequence[] = {
+ { XMM7360_RPC_CALL_UTA_MS_SMS_INIT, FALSE, NULL, 3, FALSE, mm_broadband_modem_xmm7360_rpc_response_processor_continue_on_success },
+ { XMM7360_RPC_CALL_UTA_MS_CBS_INIT, FALSE, NULL, 3, FALSE, mm_broadband_modem_xmm7360_rpc_response_processor_continue_on_success },
+ { XMM7360_RPC_CALL_UTA_MS_NET_OPEN, FALSE, NULL, 3, FALSE, mm_broadband_modem_xmm7360_rpc_response_processor_continue_on_success },
+ { XMM7360_RPC_CALL_UTA_MS_NET_SET_RADIO_SIGNAL_REPORTING, FALSE, set_radio_signal_reporting_args, 3, FALSE, mm_broadband_modem_xmm7360_rpc_response_processor_continue_on_success},
+ { XMM7360_RPC_CALL_UTA_MS_CALL_CS_INIT, FALSE, NULL, 3, FALSE, mm_broadband_modem_xmm7360_rpc_response_processor_continue_on_success },
+ { XMM7360_RPC_CALL_UTA_MS_CALL_PS_INITIALIZE, FALSE, NULL, 3, FALSE, mm_broadband_modem_xmm7360_rpc_response_processor_continue_on_success },
+ { XMM7360_RPC_CALL_UTA_MS_SS_INIT, FALSE, NULL, 3, FALSE, mm_broadband_modem_xmm7360_rpc_response_processor_continue_on_success },
+ { XMM7360_RPC_CALL_UTA_MS_SIM_OPEN_REQ, FALSE, NULL, 3, FALSE, mm_broadband_modem_xmm7360_rpc_response_processor_final },
+ { 0 }
+};
+
+static void
+initialization_started (MMBroadbandModem *modem,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ MMBroadbandModemXmm7360 *self = MM_BROADBAND_MODEM_XMM7360 (modem);
+ InitializationStartedContext *ctx;
+ GTask *task;
+
+ task = g_task_new (self,
+ NULL,
+ (GAsyncReadyCallback)initialization_started_ready,
+ g_task_new (self, NULL, callback, user_data));
+
+ ctx = g_slice_new0 (InitializationStartedContext);
+ ctx->port = mm_broadband_modem_xmm7360_get_port_xmmrpc (self);
+ ctx->is_sim_initialized = FALSE;
+ ctx->timeout_id = 0;
+ g_task_set_task_data (task, ctx, (GDestroyNotify)initialization_started_context_free);
+
+ /* Open XMMRPC port for initialization */
+ if (!mm_port_serial_open (MM_PORT_SERIAL (ctx->port), &error)) {
+ g_prefix_error (&error, "Couldn't open XMMRPC port during initialization: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ ctx->unsol_handler_id = mm_port_serial_xmmrpc_xmm7360_add_unsolicited_msg_handler (
+ ctx->port,
+ (MMPortSerialXmmrpcXmm7360UnsolicitedMsgFn)init_unsol_handler,
+ task,
+ NULL);
+
+ mm_obj_dbg (self, "running init sequence...");
+ mm_broadband_modem_xmm7360_rpc_sequence_full (MM_BROADBAND_MODEM_XMM7360 (self),
+ ctx->port,
+ init_sequence,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)init_sequence_ready,
+ task);
+}
+
+/*****************************************************************************/
+
+MMBroadbandModemXmm7360 *
+mm_broadband_modem_xmm7360_new (const gchar *device,
+ const gchar *physdev,
+ const gchar **drivers,
+ const gchar *plugin,
+ guint16 vendor_id,
+ guint16 product_id)
+{
+ return g_object_new (MM_TYPE_BROADBAND_MODEM_XMM7360,
+ MM_BASE_MODEM_DEVICE, device,
+ MM_BASE_MODEM_PHYSDEV, physdev,
+ MM_BASE_MODEM_DRIVERS, drivers,
+ MM_BASE_MODEM_PLUGIN, plugin,
+ MM_BASE_MODEM_VENDOR_ID, vendor_id,
+ MM_BASE_MODEM_PRODUCT_ID, product_id,
+ MM_BASE_MODEM_DATA_NET_SUPPORTED, TRUE,
+ MM_BASE_MODEM_DATA_TTY_SUPPORTED, TRUE,
+ NULL);
+}
+
+static void
+mm_broadband_modem_xmm7360_init (MMBroadbandModemXmm7360 *self)
+{
+ /* Initialize private data */
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ MM_TYPE_BROADBAND_MODEM_XMM7360,
+ MMBroadbandModemXmm7360Private);
+}
+
+static void
+dispose (GObject *object)
+{
+ MMBroadbandModemXmm7360 *self = MM_BROADBAND_MODEM_XMM7360 (object);
+
+ g_clear_object (&self->priv->unlock_retries);
+
+ G_OBJECT_CLASS (mm_broadband_modem_xmm7360_parent_class)->dispose (object);
+}
+
+
+static void
+iface_modem_init (MMIfaceModemInterface *iface)
+{
+ iface_modem_parent = g_type_interface_peek_parent (iface);
+ iface->modem_power_up = modem_power_up;
+ iface->modem_power_up_finish = modem_power_up_finish;
+ iface->create_bearer = create_bearer;
+ iface->create_bearer_finish = create_bearer_finish;
+ iface->create_sim = create_sim;
+ iface->create_sim_finish = create_sim_finish;
+}
+
+static void
+iface_modem_3gpp_init (MMIfaceModem3gppInterface *iface)
+{
+ iface->set_initial_eps_bearer_settings = modem_3gpp_set_initial_eps_bearer_settings;
+ iface->set_initial_eps_bearer_settings_finish = modem_3gpp_set_initial_eps_bearer_settings_finish;
+}
+
+static void
+iface_modem_location_init (MMIfaceModemLocationInterface *iface)
+{
+ /* asking for location capabilities can destabilize the device */
+ iface->load_capabilities = NULL;
+ iface->load_capabilities_finish = NULL;
+ iface->enable_location_gathering = NULL;
+ iface->enable_location_gathering_finish = NULL;
+}
+
+static void
+mm_broadband_modem_xmm7360_class_init (MMBroadbandModemXmm7360Class *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMBroadbandModemXmm7360Private));
+
+ object_class->dispose = dispose;
+
+ broadband_modem_class->initialization_started = initialization_started;
+ broadband_modem_class->initialization_started_finish = initialization_started_finish;
+}
diff --git a/src/plugins/intel/mm-broadband-modem-xmm7360.h b/src/plugins/intel/mm-broadband-modem-xmm7360.h
new file mode 100644
index 00000000..99f68abf
--- /dev/null
+++ b/src/plugins/intel/mm-broadband-modem-xmm7360.h
@@ -0,0 +1,71 @@
+/* -*- 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) 2019 James Wah
+ * Copyright (C) 2020 Marinus Enzinger <marinus@enzingerm.de>
+ * Copyright (C) 2023 Shane Parslow
+ * Copyright (c) 2024 Thomas Vogt
+ */
+
+#ifndef MM_BROADBAND_MODEM_XMM7360_H
+#define MM_BROADBAND_MODEM_XMM7360_H
+
+#include "mm-broadband-modem.h"
+#include "mm-port-serial-xmmrpc-xmm7360.h"
+
+#define MM_TYPE_BROADBAND_MODEM_XMM7360 (mm_broadband_modem_xmm7360_get_type ())
+#define MM_BROADBAND_MODEM_XMM7360(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_XMM7360, MMBroadbandModemXmm7360))
+#define MM_BROADBAND_MODEM_XMM7360_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_XMM7360, MMBroadbandModemXmm7360Class))
+#define MM_IS_BROADBAND_MODEM_XMM7360(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_XMM7360))
+#define MM_IS_BROADBAND_MODEM_XMM7360_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_XMM7360))
+#define MM_BROADBAND_MODEM_XMM7360_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_XMM7360, MMBroadbandModemXmm7360Class))
+
+typedef struct _MMBroadbandModemXmm7360 MMBroadbandModemXmm7360;
+typedef struct _MMBroadbandModemXmm7360Class MMBroadbandModemXmm7360Class;
+typedef struct _MMBroadbandModemXmm7360Private MMBroadbandModemXmm7360Private;
+
+struct _MMBroadbandModemXmm7360 {
+ MMBroadbandModem parent;
+ MMBroadbandModemXmm7360Private *priv;
+};
+
+struct _MMBroadbandModemXmm7360Class{
+ MMBroadbandModemClass parent;
+};
+
+GType mm_broadband_modem_xmm7360_get_type (void);
+
+MMBroadbandModemXmm7360 *mm_broadband_modem_xmm7360_new (const gchar *device,
+ const gchar *physdev,
+ const gchar **driver,
+ const gchar *plugin,
+ guint16 vendor_id,
+ guint16 product_id);
+
+MMPortSerialXmmrpcXmm7360 *mm_broadband_modem_xmm7360_get_port_xmmrpc (MMBroadbandModemXmm7360 *self);
+MMPortSerialXmmrpcXmm7360 *mm_broadband_modem_xmm7360_peek_port_xmmrpc (MMBroadbandModemXmm7360 *self);
+
+void mm_broadband_modem_xmm7360_check_fcc_lock (MMBroadbandModemXmm7360 *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ MMPortSerialXmmrpcXmm7360 *port,
+ gboolean unlock);
+
+gboolean mm_broadband_modem_xmm7360_check_fcc_lock_finish (MMBroadbandModemXmm7360 *self,
+ GAsyncResult *res,
+ GError **error);
+
+void mm_broadband_modem_xmm7360_set_unlock_retries (MMBroadbandModemXmm7360 *self,
+ MMModemLock lock_type,
+ guint32 remaining_attempts);
+
+#endif /* MM_BROADBAND_MODEM_XMM7360_H */
diff --git a/src/plugins/intel/mm-plugin-intel.c b/src/plugins/intel/mm-plugin-intel.c
index 20392114..571c0a0a 100644
--- a/src/plugins/intel/mm-plugin-intel.c
+++ b/src/plugins/intel/mm-plugin-intel.c
@@ -11,6 +11,7 @@
* GNU General Public License for more details:
*
* Copyright (C) 2021-2022 Intel Corporation
+ * Copyright (c) 2024 Thomas Vogt
*/
#include <stdio.h>
@@ -23,6 +24,7 @@
#include "mm-log-object.h"
#include "mm-broadband-modem.h"
+#include "mm-broadband-modem-xmm7360.h"
#if defined WITH_MBIM
#include "mm-broadband-modem-mbim-intel.h"
#endif
@@ -57,15 +59,19 @@ create_modem (MMPlugin *self,
#endif
if (mm_port_probe_list_has_xmmrpc_port (probes)) {
- mm_obj_dbg (self, "Intel modem with RPC control port found...");
if (product == 0x7360) {
- g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
- "Intel XMM7360 in RPC mode not supported");
- return NULL;
+ mm_obj_dbg (self, "Intel XMM7360 in RPC mode found...");
+ return MM_BASE_MODEM (mm_broadband_modem_xmm7360_new (uid,
+ physdev,
+ drivers,
+ mm_plugin_get_name (self),
+ vendor,
+ product));
+ } else {
+ mm_obj_dbg (self, "Ignoring unknown XMMRPC control port...");
}
}
-
mm_obj_dbg (self, "Generic Intel modem found...");
return MM_BASE_MODEM (mm_broadband_modem_new (uid,
physdev,
diff --git a/src/plugins/intel/mm-port-serial-xmmrpc-xmm7360.c b/src/plugins/intel/mm-port-serial-xmmrpc-xmm7360.c
new file mode 100644
index 00000000..96c09180
--- /dev/null
+++ b/src/plugins/intel/mm-port-serial-xmmrpc-xmm7360.c
@@ -0,0 +1,750 @@
+/* -*- 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) 2019 James Wah
+ * Copyright (C) 2020 Marinus Enzinger <marinus@enzingerm.de>
+ * Copyright (C) 2023 Shane Parslow
+ * Copyright (C) 2024 Thomas Vogt
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "mm-log-object.h"
+
+#include "mm-port-serial-xmmrpc-xmm7360.h"
+#include "mm-intel-enums-types.h"
+
+G_DEFINE_TYPE (MMPortSerialXmmrpcXmm7360, mm_port_serial_xmmrpc_xmm7360, MM_TYPE_PORT_SERIAL)
+
+struct _MMPortSerialXmmrpcXmm7360Private {
+ GSList *unsolicited_msg_handlers;
+ guint unsolicited_msg_handlers_i;
+};
+
+static void
+xmm7360_rpc_msg_arg_free (Xmm7360RpcMsgArg *arg)
+{
+ if (arg->type == XMM7360_RPC_MSG_ARG_TYPE_STRING) {
+ g_free ((gchar *) arg->value.string);
+ }
+ g_free (arg);
+}
+
+void
+xmm7360_rpc_response_free (Xmm7360RpcResponse *response)
+{
+ if (response) {
+ g_byte_array_free (response->body, TRUE);
+ g_ptr_array_free (response->content, TRUE);
+ g_free (response);
+ }
+}
+
+static gint
+xmm7360_byte_array_read_asn_int (GByteArray *buf, gsize *offset, Xmm7360RpcMsgArg *arg)
+{
+ gint size;
+ gint bytes_read;
+ gint val;
+
+ g_assert (buf->len > *offset + 2);
+
+ /* check ASN start byte and read int size */
+ g_assert (buf->data[(*offset)++] == 0x02);
+ size = buf->data[(*offset)++];
+
+ /* read actual value byte by byte */
+ g_assert (buf->len >= *offset + size);
+ val = 0;
+ for (bytes_read = 0; bytes_read < size; bytes_read++) {
+ val <<= 8;
+ val |= buf->data[(*offset)++];
+ }
+
+ if (arg != NULL) {
+ if (size == 0x01) {
+ arg->type = XMM7360_RPC_MSG_ARG_TYPE_BYTE;
+ arg->value.b = (gint8) val;
+ } else if (size == 0x02) {
+ arg->type = XMM7360_RPC_MSG_ARG_TYPE_SHORT;
+ arg->value.s = (gint16) val;
+ } else {
+ arg->type = XMM7360_RPC_MSG_ARG_TYPE_LONG;
+ arg->value.l = (gint32) val;
+ }
+ }
+
+ return val;
+}
+
+static gchar *
+xmm7360_byte_array_read_string (GByteArray *buf, gsize *offset, gsize *string_len)
+{
+ guchar string_type;
+ gsize string_len_padded;
+ gsize pad_len;
+ gchar *result;
+
+ g_assert (buf->len > *offset + 2);
+
+ string_type = buf->data[(*offset)++];
+ g_assert (string_type == 0x55 || string_type == 0x56 || string_type == 0x57);
+
+ *string_len = buf->data[(*offset)++];
+ if (*string_len & 0x80) {
+ guchar bytelen;
+ guchar i;
+
+ bytelen = *string_len & 0x0f;
+ *string_len = 0;
+ g_assert (bytelen <= 4);
+ g_assert (buf->len > *offset + bytelen);
+ for (i = 0; i < bytelen; i++) {
+ *string_len |= buf->data[(*offset)++] << (i * 8);
+ }
+ }
+
+ if (string_type == 0x56) {
+ /* 0x56 contains 2-byte chars */
+ *string_len <<= 1;
+ } else if (string_type == 0x57) {
+ /* 0x57 contains 4-byte chars */
+ *string_len <<= 2;
+ }
+
+ string_len_padded = (gsize) xmm7360_byte_array_read_asn_int (buf, offset, NULL);
+ pad_len = (gsize) xmm7360_byte_array_read_asn_int (buf, offset, NULL);
+
+ if (string_len_padded > 0) {
+ g_assert (string_len_padded == *string_len + pad_len);
+ } else {
+ string_len_padded = *string_len + pad_len;
+ }
+
+ /* make sure the buffer is large enough */
+ g_assert (buf->len >= *offset + string_len_padded);
+
+ /* copy the result */
+ result = g_malloc (*string_len);
+ memcpy (result, &(buf->data[*offset]), *string_len);
+
+ /* move pointer to the end of the string data */
+ *offset += (*string_len + pad_len);
+
+ return result;
+}
+
+
+void
+xmm7360_byte_array_append_asn_int4 (GByteArray *buf, gint32 value)
+{
+ gint32 value_be = GINT32_TO_BE (value);
+ g_byte_array_append (buf, (const guint8 *) "\x02\x04", 2);
+ g_byte_array_append (buf, (const guint8 *) &value_be, 4);
+}
+
+static void
+xmm7360_byte_array_append_uint8 (GByteArray *buf, gulong val)
+{
+ guint8 _val = (guint8) val;
+ g_byte_array_append (buf, &_val, 1);
+}
+
+static void
+xmm7360_byte_array_append_string (GByteArray *buf,
+ const guint8 *data,
+ gsize data_len,
+ guint data_len_padded)
+{
+ gsize i;
+ gsize pad_len;
+
+ g_assert (data_len_padded >= data_len);
+ pad_len = data_len_padded - data_len;
+
+ /* only support 1-byte element size */
+ xmm7360_byte_array_append_uint8 (buf, 0x55);
+
+ if (data_len < 0x80) {
+ xmm7360_byte_array_append_uint8 (buf, data_len);
+ } else {
+ guchar bytelen = 0x80;
+ /* write dummy first byte (updated later) */
+ xmm7360_byte_array_append_uint8 (buf, bytelen);
+ for (i = data_len; i > 0; i >>= 8) {
+ bytelen++;
+ xmm7360_byte_array_append_uint8 (buf, i & 0xff);
+ }
+ /* update first byte */
+ buf->data[buf->len - 1 - (bytelen & 0x7f)] = bytelen;
+ }
+
+ xmm7360_byte_array_append_asn_int4 (buf, data_len_padded);
+ xmm7360_byte_array_append_asn_int4 (buf, pad_len);
+ g_byte_array_append (buf, data, data_len);
+ for (i = 0; i < pad_len; i++) {
+ xmm7360_byte_array_append_uint8 (buf, 0);
+ }
+}
+
+static GString *
+xmm7360_byte_array_hexlify (GByteArray *buf) {
+ GString *string;
+ gsize i;
+
+ string = g_string_sized_new (2 * buf->len + 1);
+ for (i = 0; i < buf->len; i++) {
+ g_string_append_printf (string, "%02x", buf->data[i]);
+ }
+ g_string_append (string, "");
+
+ /* truncate very long strings to avoid overly verbose logs */
+ if (string->len > 64) {
+ gsize string_len;
+ string_len = string->len;
+ g_string_truncate (string, 48);
+ g_string_append_printf (string, "... (%ld chars)", string_len);
+ }
+
+ return string;
+}
+
+static void
+xmm7360_byte_array_log (gpointer obj, const gchar *prefix, GByteArray *buf)
+{
+ GString *hexlified;
+
+ hexlified = xmm7360_byte_array_hexlify (buf);
+ mm_obj_dbg (obj, "%sb'%s'", prefix ? prefix : "", hexlified->str);
+ g_string_free (hexlified, TRUE);
+}
+
+static GString *
+xmm7360_rpc_args_to_string (GPtrArray *args)
+{
+ guint i;
+ GString *result;
+ Xmm7360RpcMsgArg *arg;
+ gint16 arg_value_short;
+ gint32 arg_value_long;
+
+ result = g_string_new ("");
+
+ for (i = 0; i < args->len; i++) {
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (args, i);
+ if (i > 0) {
+ g_string_append (result, " ");
+ }
+ switch (arg->type) {
+ case XMM7360_RPC_MSG_ARG_TYPE_BYTE:
+ g_string_append_printf (result, "B(0x%02x)", arg->value.b);
+ break;
+ case XMM7360_RPC_MSG_ARG_TYPE_SHORT:
+ arg_value_short = GINT16_TO_BE (arg->value.s);
+ g_string_append_printf (result, "S(0x%04x)", arg_value_short);
+ break;
+ case XMM7360_RPC_MSG_ARG_TYPE_LONG:
+ arg_value_long = GINT32_TO_BE (arg->value.l);
+ g_string_append_printf (result, "L(0x%08x)", arg_value_long);
+ break;
+ case XMM7360_RPC_MSG_ARG_TYPE_STRING:
+ g_string_append_printf (result, "STR(size=%ld)", arg->size);
+ break;
+ case XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN:
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ return result;
+}
+
+static void
+xmm7360_rpc_msg_args_log (gpointer obj, const gchar *prefix, GPtrArray *args)
+{
+ GString *args_string;
+
+ args_string = xmm7360_rpc_args_to_string (args);
+
+ /* truncate very long strings to avoid overly verbose logs */
+ if (args_string->len > 64) {
+ g_string_truncate (args_string, 58);
+ g_string_append_printf (args_string, "... (%d args)", args->len);
+ }
+
+ mm_obj_dbg (obj, "%s%s", prefix ? prefix : "", args_string->str);
+ g_string_free (args_string, TRUE);
+}
+
+GByteArray *
+xmm7360_rpc_args_to_byte_array (const Xmm7360RpcMsgArg *args)
+{
+ GByteArray *result;
+ gint16 arg_value_short;
+ gint32 arg_value_long;
+
+ if (args == NULL)
+ return NULL;
+
+ result = g_byte_array_new ();
+ for (; args->type != XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN; args++) {
+ switch (args->type) {
+ case XMM7360_RPC_MSG_ARG_TYPE_BYTE:
+ g_byte_array_append (result, (guint8[]) { 0x02, 0x01 }, 2);
+ g_byte_array_append (result, (guint8 *) &(args->value.b), 1);
+ break;
+ case XMM7360_RPC_MSG_ARG_TYPE_SHORT:
+ arg_value_short = GINT16_TO_BE (args->value.s);
+ g_byte_array_append (result, (guint8[]) { 0x02, 0x02 }, 2);
+ g_byte_array_append (result, (guint8 *) &arg_value_short, 2);
+ break;
+ case XMM7360_RPC_MSG_ARG_TYPE_LONG:
+ arg_value_long = GINT32_TO_BE (args->value.l);
+ g_byte_array_append (result, (guint8[]) { 0x02, 0x04 }, 2);
+ g_byte_array_append (result, (guint8 *) &arg_value_long, 4);
+ break;
+ case XMM7360_RPC_MSG_ARG_TYPE_STRING:
+ xmm7360_byte_array_append_string (result,
+ (const guint8 *) args->value.string,
+ args->size,
+ args->size + args->pad);
+ break;
+ case XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN:
+ default:
+ /* should be unreachable */
+ return NULL;
+ }
+ }
+ return result;
+}
+
+static GByteArray *
+xmm7360_command_to_byte_array (Xmm7360RpcCallId callid,
+ gboolean is_async,
+ GByteArray *body)
+{
+ GByteArray *buf;
+ gint32 tid;
+ gint32 tid_word;
+ gint32 tid_word_be;
+ guint32 total_len;
+
+ buf = g_byte_array_sized_new (22);
+
+ if (body == NULL) {
+ body = g_byte_array_new ();
+ xmm7360_byte_array_append_asn_int4 (body, 0);
+ } else {
+ g_byte_array_ref (body);
+ }
+
+ if (is_async) {
+ tid = 0x11000101;
+ } else {
+ tid = 0;
+ }
+ tid_word = 0x11000100 | tid;
+
+ total_len = body->len + 16;
+ if (tid) {
+ total_len += 6;
+ }
+ g_byte_array_append (buf, (const guint8 *) &total_len, 4);
+ xmm7360_byte_array_append_asn_int4 (buf, total_len);
+ xmm7360_byte_array_append_asn_int4 (buf, callid);
+ tid_word_be = GINT32_TO_BE (tid_word);
+ g_byte_array_append (buf, (const guint8 *) &tid_word_be, 4);
+ if (tid) {
+ xmm7360_byte_array_append_asn_int4 (buf, tid);
+ }
+
+ g_assert (total_len == buf->len + body->len - 4);
+ g_byte_array_append (buf, (const guint8 *) body->data, body->len);
+ g_byte_array_unref (body);
+
+ return buf;
+}
+
+static int
+xmm7360_rpc_msg_body_unpack (GByteArray *buf, GPtrArray *args, GError **error)
+{
+ GError *inner_error = NULL;
+ gsize offset;
+ gchar *str_value;
+ Xmm7360RpcMsgArg *arg;
+
+ g_assert (buf != NULL && args != NULL);
+
+ offset = 0;
+ while (offset < buf->len) {
+ arg = g_new0 (Xmm7360RpcMsgArg, 1);
+ arg->size = 0;
+ switch (buf->data[offset]) {
+ case 0x02:
+ xmm7360_byte_array_read_asn_int (buf, &offset, arg);
+ break;
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ arg->type = XMM7360_RPC_MSG_ARG_TYPE_STRING;
+ str_value = xmm7360_byte_array_read_string (buf, &offset, &arg->size);
+ if (str_value == NULL) {
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Parsing a string failed");
+ goto out;
+ }
+ arg->value.string = str_value;
+ break;
+ default:
+ arg->type = XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN;
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Unknown type 0x%x",
+ buf->data[offset]);
+ goto out;
+ }
+ g_ptr_array_add (args, arg);
+ }
+
+out:
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return -1;
+ }
+
+ return 0;
+}
+
+static Xmm7360RpcResponse *
+parse_response_xmm7360 (GByteArray *buf)
+{
+ GError *error = NULL;
+ Xmm7360RpcResponse *response = NULL;
+ gsize offset;
+ Xmm7360RpcMsgArg *arg;
+
+ /* first 20 bytes are format header:
+ * message size ( int32, 4)
+ * message size (again!) (asn int, 6)
+ * unsolicited message id (asn int, 6)
+ * transmission id ( int32, 4)
+ */
+ g_assert (buf->len > 20);
+
+ offset = 4;
+ if (*(gint32 *) buf->data != xmm7360_byte_array_read_asn_int (buf, &offset, NULL)) {
+ mm_obj_dbg (NULL, "error parsing RPC message: length mismatch");
+ goto err;
+ }
+
+ /* initialize all fields of the response */
+ response = g_new0 (Xmm7360RpcResponse, 1);
+ response->id = GINT32_FROM_BE (*(gint32 *) (buf->data + 16));
+ response->type = XMM7360_RPC_RESPONSE_TYPE_UNKNOWN;
+ response->unsol_id = xmm7360_byte_array_read_asn_int (buf, &offset, NULL);
+ response->body = g_byte_array_new ();
+ response->content = g_ptr_array_new_with_free_func ((GDestroyNotify)xmm7360_rpc_msg_arg_free);
+
+ g_byte_array_append (response->body, &buf->data[20], buf->len - 20);
+ if (xmm7360_rpc_msg_body_unpack (response->body, response->content, &error) != 0) {
+ mm_obj_dbg (NULL, "error parsing RPC message: unpacking failed: %s", error->message);
+ g_error_free (error);
+ goto err;
+ }
+
+ if (response->id == 0x11000100) {
+ response->type = XMM7360_RPC_RESPONSE_TYPE_RESPONSE;
+ } else if ((response->id & 0xffffff00) == 0x11000100) {
+ if (response->unsol_id >= 0x7d0) {
+ response->type = XMM7360_RPC_RESPONSE_TYPE_ASYNC_ACK;
+ } else {
+ response->type = XMM7360_RPC_RESPONSE_TYPE_RESPONSE;
+
+ /* discard first element in content (equals transmission id) */
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 0);
+ if (arg->type != XMM7360_RPC_MSG_ARG_TYPE_LONG
+ || (guint32) XMM7360_RPC_MSG_ARG_GET_INT (arg) != response->id) {
+ mm_obj_dbg (NULL, "error parsing RPC message: invalid start of async response body");
+ goto err;
+ }
+ g_ptr_array_remove_index (response->content, 0);
+ g_byte_array_remove_range (response->body, 0, 6);
+ }
+ } else {
+ response->type = XMM7360_RPC_RESPONSE_TYPE_UNSOLICITED;
+ }
+
+ return response;
+
+err:
+ if (response)
+ xmm7360_rpc_response_free (response);
+ return NULL;
+}
+
+static MMPortSerialResponseType
+parse_response (MMPortSerial *port,
+ GByteArray *response_buffer,
+ GByteArray **parsed_response,
+ GError **error)
+{
+ if (!response_buffer->len)
+ return MM_PORT_SERIAL_RESPONSE_NONE;
+
+ *parsed_response = g_byte_array_new ();
+ g_byte_array_append (*parsed_response, response_buffer->data, response_buffer->len);
+
+ /* Fully cleanup the response array, we'll consider the contents we got
+ * as the full reply that the command may expect. */
+ g_byte_array_remove_range (response_buffer, 0, response_buffer->len);
+
+ return MM_PORT_SERIAL_RESPONSE_BUFFER;
+}
+
+static void
+serial_command_ready (MMPortSerial *port,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GByteArray *response_buffer;
+ GError *error = NULL;
+ Xmm7360RpcResponse *response;
+
+ response_buffer = mm_port_serial_command_finish (port, res, &error);
+ if (!response_buffer) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ response = parse_response_xmm7360 (response_buffer);
+ if (response_buffer->len > 0)
+ g_byte_array_remove_range (response_buffer, 0, response_buffer->len);
+ g_byte_array_unref (response_buffer);
+
+ g_task_return_pointer (task, response, (GDestroyNotify) xmm7360_rpc_response_free);
+ g_object_unref (task);
+}
+
+Xmm7360RpcResponse *
+mm_port_serial_xmmrpc_xmm7360_command_finish (MMPortSerialXmmrpcXmm7360 *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_pointer (G_TASK (res), error);
+}
+
+void
+mm_port_serial_xmmrpc_xmm7360_command (MMPortSerialXmmrpcXmm7360 *self,
+ Xmm7360RpcCallId callid,
+ gboolean is_async,
+ GByteArray *body,
+ guint32 timeout_seconds,
+ gboolean allow_cached,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GByteArray) buf = NULL;
+ GTask *task;
+
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (MM_IS_PORT_SERIAL_XMMRPC_XMM7360 (self));
+
+ buf = xmm7360_command_to_byte_array (callid, is_async, body);
+ g_return_if_fail (buf != NULL);
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ mm_obj_dbg (self, "--> %s%s", is_async ? "(async) " : "", xmm_7360_rpc_call_id_get_string (callid));
+
+ xmm7360_byte_array_log (self, "", buf);
+
+ mm_port_serial_command (MM_PORT_SERIAL (self),
+ buf,
+ timeout_seconds,
+ allow_cached,
+ TRUE, /* raw commands always run next, never queued last */
+ cancellable,
+ (GAsyncReadyCallback)serial_command_ready,
+ task);
+}
+
+/*****************************************************************************/
+
+typedef struct {
+ guint id;
+ MMPortSerialXmmrpcXmm7360UnsolicitedMsgFn callback;
+ gboolean enable;
+ gpointer user_data;
+ GDestroyNotify notify;
+} MMRpcUnsolicitedMsgHandler;
+
+static gint
+unsolicited_msg_handler_cmp (MMRpcUnsolicitedMsgHandler *handler, guint *id)
+{
+ return handler->id == *id;
+}
+
+guint
+mm_port_serial_xmmrpc_xmm7360_add_unsolicited_msg_handler (MMPortSerialXmmrpcXmm7360 *self,
+ MMPortSerialXmmrpcXmm7360UnsolicitedMsgFn callback,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ MMRpcUnsolicitedMsgHandler *handler;
+
+ g_return_val_if_fail (MM_IS_PORT_SERIAL_XMMRPC_XMM7360 (self), 0);
+
+ handler = g_slice_new (MMRpcUnsolicitedMsgHandler);
+ handler->id = ++(self->priv->unsolicited_msg_handlers_i);
+ handler->callback = callback;
+ handler->enable = TRUE;
+ handler->user_data = user_data;
+ handler->notify = notify;
+
+ /* The new handler is always PREPENDED */
+ self->priv->unsolicited_msg_handlers = g_slist_prepend (self->priv->unsolicited_msg_handlers, handler);
+
+ return handler->id;
+}
+
+void
+mm_port_serial_xmmrpc_xmm7360_enable_unsolicited_msg_handler (MMPortSerialXmmrpcXmm7360 *self,
+ guint handler_id,
+ gboolean enable)
+{
+ GSList *existing;
+ MMRpcUnsolicitedMsgHandler *handler;
+
+ g_return_if_fail (MM_IS_PORT_SERIAL_XMMRPC_XMM7360 (self));
+
+ existing = g_slist_find_custom (self->priv->unsolicited_msg_handlers,
+ &handler_id,
+ (GCompareFunc)unsolicited_msg_handler_cmp);
+ if (existing) {
+ handler = existing->data;
+ handler->enable = enable;
+ }
+}
+
+static void
+parse_unsolicited (MMPortSerial *port, GByteArray *response_buffer)
+{
+ MMPortSerialXmmrpcXmm7360 *self = MM_PORT_SERIAL_XMMRPC_XMM7360 (port);
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+ GSList *iter;
+
+ response = parse_response_xmm7360 (response_buffer);
+
+ if (!response) {
+ return;
+ }
+
+ if (response->type == XMM7360_RPC_RESPONSE_TYPE_RESPONSE) {
+ mm_obj_dbg (port, "<-- (response)");
+ xmm7360_byte_array_log (port, "", response->body);
+ xmm7360_rpc_msg_args_log (port, "", response->content);
+ return;
+ }
+
+ if (response->type == XMM7360_RPC_RESPONSE_TYPE_ASYNC_ACK) {
+ /* discard ASYNC_ACK message since the RESPONSE is expected to follow later
+ * empty the buffer to show that the message is dealt with
+ */
+ mm_obj_dbg (port, "<-- (async-ack)");
+ g_byte_array_remove_range (response_buffer, 0, response_buffer->len);
+ return;
+ }
+
+ mm_obj_dbg (port, "<-- (unsolicited) %s",
+ xmm_7360_rpc_unsol_id_get_string (response->unsol_id));
+ xmm7360_byte_array_log (port, "", response->body);
+ xmm7360_rpc_msg_args_log (port, "", response->content);
+
+ for (iter = self->priv->unsolicited_msg_handlers; iter; iter = iter->next) {
+ MMRpcUnsolicitedMsgHandler *handler = (MMRpcUnsolicitedMsgHandler *) iter->data;
+
+ if (!handler->enable)
+ continue;
+
+ if (handler->callback (self, response, handler->user_data)) {
+ /* if successful, empty the buffer to show that the message is dealt with */
+ g_byte_array_remove_range (response_buffer, 0, response_buffer->len);
+ return;
+ }
+ }
+
+ /* unhandled unsolicited message is discarded */
+ g_byte_array_remove_range (response_buffer, 0, response_buffer->len);
+}
+
+/*****************************************************************************/
+
+MMPortSerialXmmrpcXmm7360 *
+mm_port_serial_xmmrpc_xmm7360_new (const char *name)
+{
+ return MM_PORT_SERIAL_XMMRPC_XMM7360 (g_object_new (MM_TYPE_PORT_SERIAL_XMMRPC_XMM7360,
+ MM_PORT_DEVICE, name,
+ MM_PORT_SUBSYS, MM_PORT_SUBSYS_WWAN,
+ MM_PORT_TYPE, MM_PORT_TYPE_XMMRPC,
+ NULL));
+}
+
+static void
+mm_port_serial_xmmrpc_xmm7360_init (MMPortSerialXmmrpcXmm7360 *self)
+{
+ /* Initialize private data */
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ MM_TYPE_PORT_SERIAL_XMMRPC_XMM7360,
+ MMPortSerialXmmrpcXmm7360Private);
+
+ self->priv->unsolicited_msg_handlers_i = 0;
+ self->priv->unsolicited_msg_handlers = NULL;
+}
+
+static void
+finalize (GObject *object)
+{
+ MMPortSerialXmmrpcXmm7360 *self = MM_PORT_SERIAL_XMMRPC_XMM7360 (object);
+
+ while (self->priv->unsolicited_msg_handlers) {
+ MMRpcUnsolicitedMsgHandler *handler = (MMRpcUnsolicitedMsgHandler *) self->priv->unsolicited_msg_handlers->data;
+
+ if (handler->notify)
+ handler->notify (handler->user_data);
+
+ g_slice_free (MMRpcUnsolicitedMsgHandler, handler);
+ self->priv->unsolicited_msg_handlers = g_slist_delete_link (self->priv->unsolicited_msg_handlers,
+ self->priv->unsolicited_msg_handlers);
+ }
+
+ G_OBJECT_CLASS (mm_port_serial_xmmrpc_xmm7360_parent_class)->finalize (object);
+}
+
+static void
+mm_port_serial_xmmrpc_xmm7360_class_init (MMPortSerialXmmrpcXmm7360Class *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMPortSerialClass *serial_class = MM_PORT_SERIAL_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMPortSerialXmmrpcXmm7360Private));
+
+ object_class->finalize = finalize;
+
+ serial_class->parse_response = parse_response;
+ serial_class->parse_unsolicited = parse_unsolicited;
+}
diff --git a/src/plugins/intel/mm-port-serial-xmmrpc-xmm7360.h b/src/plugins/intel/mm-port-serial-xmmrpc-xmm7360.h
new file mode 100644
index 00000000..59cc0dd6
--- /dev/null
+++ b/src/plugins/intel/mm-port-serial-xmmrpc-xmm7360.h
@@ -0,0 +1,590 @@
+/* -*- 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) 2019 James Wah
+ * Copyright (C) 2020 Marinus Enzinger <marinus@enzingerm.de>
+ * Copyright (C) 2023 Shane Parslow
+ * Copyright (C) 2024 Thomas Vogt
+ */
+
+#ifndef MM_PORT_SERIAL_XMMRPC_XMM7360_H
+#define MM_PORT_SERIAL_XMMRPC_XMM7360_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "mm-port-serial.h"
+
+typedef enum {
+ XMM7360_RPC_CALL_UTA_MS_SIM_OPEN_REQ = 0x001,
+ XMM7360_RPC_CALL_UTA_MS_SIM_APDU_CMD_REQ = 0x002,
+ XMM7360_RPC_CALL_UTA_MS_SIM_APPLICATION_REQ = 0x004,
+ XMM7360_RPC_CALL_UTA_MS_SIM_DECODE_FCP = 0x006,
+ XMM7360_RPC_CALL_UTA_MS_SIM_PB_READ_ENTRY_REQ = 0x00d,
+ XMM7360_RPC_CALL_UTA_MS_SIM_GEN_PIN_REQ = 0x00f,
+ XMM7360_RPC_CALL_UTA_MS_SIM_MODIFY_LOCK_REQ = 0x011,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_PROACTIVE_COMMAND_RSP = 0x016,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_ENVELOPE_COMMAND_REQ = 0x017,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_TERMINAL_PROFILE_READ_REQ = 0x019,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_REGISTER_HANDLER = 0x01c,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_DEREGISTER_HANDLER = 0x01d,
+ XMM7360_RPC_CALL_UTA_MS_CPS_SET_MODE_REQ = 0x01f,
+ XMM7360_RPC_CALL_UTA_MS_CPS_SET_STACK_MODE_CONFIGURATION = 0x020,
+ XMM7360_RPC_CALL_UTA_MS_CPS_SET_SIM_MODE_CONFIGURATION = 0x021,
+ XMM7360_RPC_CALL_UTA_MS_CPS_READ_IMEI = 0x023,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_INIT = 0x024,
+ XMM7360_RPC_CALL_UTA_MS_CBS_INIT = 0x025,
+ XMM7360_RPC_CALL_UTA_MS_SS_INIT = 0x026,
+ XMM7360_RPC_CALL_UTA_MS_SS_SEND_USSD_REQ = 0x027,
+ XMM7360_RPC_CALL_UTA_MS_SS_RESPOND_USSD = 0x028,
+ XMM7360_RPC_CALL_UTA_MS_SS_ABORT = 0x029,
+ XMM7360_RPC_CALL_UTA_MS_SMS_INIT = 0x030,
+ XMM7360_RPC_CALL_UTA_MS_SMS_SEND_REQ = 0x031,
+ XMM7360_RPC_CALL_UTA_MS_SMS_SET_MEMORY_AVAILABLE_REQ = 0x034,
+ XMM7360_RPC_CALL_UTA_MS_SMS_INCOMING_SMS_ACK = 0x036,
+ XMM7360_RPC_CALL_UTA_MS_SMS_SIM_MSG_COUNT_REQ = 0x038,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_INITIALIZE = 0x03a,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_OBTAIN_PDP_CONTEXT_ID = 0x03b,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_RELEASE_PDP_CONTEXT_ID = 0x03c,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_DEFINE_PRIMARY_REQ = 0x03d,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_UNDEFINE_PRIMARY_REQ = 0x03f,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_GET_PRIMARY_REQ = 0x041,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_SET_AUTHENTICATION_REQ = 0x043,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_SET_DNS_REQ = 0x045,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_GET_NEGOTIATED_DNS_REQ = 0x047,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_GET_NEG_IP_ADDR_REQ = 0x049,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_ACTIVATE_REQ = 0x04b,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_DEACTIVATE_REQ = 0x04e,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_CONNECT_REQ = 0x051,
+ XMM7360_RPC_CALL_UTA_MS_NET_OPEN = 0x053,
+ XMM7360_RPC_CALL_UTA_MS_NET_SET_RADIO_SIGNAL_REPORTING = 0x054,
+ XMM7360_RPC_CALL_UTA_MS_NET_SINGLE_SHOT_RADIO_SIGNAL_REPORTING_REQ = 0x055,
+ XMM7360_RPC_CALL_UTA_MS_NET_ATTACH_REQ = 0x05c,
+ XMM7360_RPC_CALL_UTA_MS_NET_PS_ATTACH_REQ = 0x05d,
+ XMM7360_RPC_CALL_UTA_MS_NET_PS_DETACH_REQ = 0x05e,
+ XMM7360_RPC_CALL_UTA_MS_NET_SCAN_REQ = 0x05f,
+ XMM7360_RPC_CALL_UTA_MS_NET_SCAN_ABORT = 0x060,
+ XMM7360_RPC_CALL_UTA_MS_NET_POWER_DOWN_REQ = 0x061,
+ XMM7360_RPC_CALL_UTA_MS_NET_EXT_SCAN_REQ = 0x062,
+ XMM7360_RPC_CALL_UTA_MS_NET_SET_FD_CONFIG_REQ = 0x06e,
+ XMM7360_RPC_CALL_UTA_MS_NET_GET_FD_CONFIG_REQ = 0x071,
+ XMM7360_RPC_CALL_UTA_MS_NET_CONFIGURE_NETWORK_MODE_REQ = 0x073,
+ XMM7360_RPC_CALL_UTA_MS_NET_RAT_MODE_STATUS_REQ = 0x076,
+ XMM7360_RPC_CALL_UTA_NVM_READ = 0x079,
+ XMM7360_RPC_CALL_UTA_NVM_WRITE = 0x07a,
+ XMM7360_RPC_CALL_UTA_NVM_WRITE_COMMIT = 0x07b,
+ XMM7360_RPC_CALL_UTA_SYS_GET_INFO = 0x07c,
+ XMM7360_RPC_CALL_UTA_RPC_PS_CONNECT_SETUP_REQ = 0x07d,
+ XMM7360_RPC_CALL_UTA_RPC_PS_CONNECT_TO_DATACHANNEL_REQ = 0x07e,
+ XMM7360_RPC_CALL_UTA_RPC_PS_CONNECT_RELEASE_REQ = 0x07f,
+ XMM7360_RPC_CALL_UTA_MS_NET_DC_SET_VOICE_DOMAIN_PREFERENCE_CONFIG_REQ = 0x080,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_SETUP_VOICE_CALL_REQ = 0x082,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_RELEASE_CALL_REQ = 0x088,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_ACCEPT_CALL_REQ = 0x08d,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_SWAP_CALLS_REQ = 0x090,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_HOLD_CALL_REQ = 0x092,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_RETRIEVE_CALL_REQ = 0x094,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_SPLIT_MPTY_REQ = 0x096,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_JOIN_CALLS_REQ = 0x098,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_TRANSFER_CALLS_REQ = 0x09a,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_START_DTMF_REQ = 0x09c,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_STOP_DTMF_REQ = 0x09e,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_SET_UUS1_INFO = 0x0a6,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_SET_TTY_DEVICE_MODE = 0x0a7,
+ XMM7360_RPC_CALL_UTA_MS_CALL_CS_GET_TTY_DEVICE_MODE = 0x0a8,
+ XMM7360_RPC_CALL_UTA_MS_CALL_MULTIMEDIA_SETUP_CALL_REQ = 0x0ac,
+ XMM7360_RPC_CALL_UTA_MS_CALL_MULTIMEDIA_UPDATE_CALL_REQ = 0x0ad,
+ XMM7360_RPC_CALL_UTA_MS_CPS_SET_SIM_MODE_REQ = 0x0b0,
+ XMM7360_RPC_CALL_UTA_MS_SS_CALL_FORWARD_REQ = 0x0b2,
+ XMM7360_RPC_CALL_UTA_MS_SS_CALL_WAITING_REQ = 0x0b4,
+ XMM7360_RPC_CALL_UTA_MS_SS_CALL_BARRING_REQ = 0x0b6,
+ XMM7360_RPC_CALL_UTA_MS_SS_IDENTIFICATION_REQ = 0x0b8,
+ XMM7360_RPC_CALL_UTA_MS_SMS_SET_SEND_MORE_MESSAGES_STATUS = 0x0ba,
+ XMM7360_RPC_CALL_UTA_MS_SMS_DATA_DOWNLOAD_REQ = 0x0bb,
+ XMM7360_RPC_CALL_UTA_MS_SMS_DATA_DOWNLOAD_ACK = 0x0bd,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_GET_NEG_QOS_REQ = 0x0be,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_GET_TFT_REQ = 0x0c0,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_SET_PCO_REQ = 0x0c2,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_GET_NW_PCO_REQ = 0x0c4,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_NW_ACTIVATE_ACCEPT_REQ = 0x0c7,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_NW_ACTIVATE_REJECT_REQ = 0x0c9,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_SET_DATA_PREF_REQ = 0x0cd,
+ XMM7360_RPC_CALL_UTA_MS_CBS_START_REQ = 0x0cf,
+ XMM7360_RPC_CALL_UTA_MS_CBS_STOP_REQ = 0x0d0,
+ XMM7360_RPC_CALL_UTA_MS_CBS_SET_MSG_FILTER = 0x0d3,
+ XMM7360_RPC_CALL_UTA_MS_CBS_GET_MSG_FILTER = 0x0d4,
+ XMM7360_RPC_CALL_UTA_MS_CBS_ETWS_CONFIG_REQ = 0x0d6,
+ XMM7360_RPC_CALL_UTA_MS_CBS_ETWS_START_REQ = 0x0d8,
+ XMM7360_RPC_CALL_UTA_MS_CBS_ETWS_STOP_REQ = 0x0da,
+ XMM7360_RPC_CALL_UTA_MS_CPS_NVM_WRITE = 0x0de,
+ XMM7360_RPC_CALL_UTA_MS_CPS_NVM_READ = 0x0df,
+ XMM7360_RPC_CALL_UTA_MS_NET_CONFIGURE_RX_DIVERSITY_DARP = 0x0e0,
+ XMM7360_RPC_CALL_UTA_MS_NET_LDR_GET_APN_PARAMETER_LIST = 0x0e2,
+ XMM7360_RPC_CALL_UTA_MS_NET_TIME_INFO_READ_REQ = 0x0e3,
+ XMM7360_RPC_CALL_UTA_MS_NET_SET_CSG_CONFIG_REQ = 0x0e6,
+ XMM7360_RPC_CALL_UTA_MS_NET_BAND_STATUS_REQ = 0x0e7,
+ XMM7360_RPC_CALL_UTA_MS_NET_GET_EXTENDED_RADIO_SIGNAL_INFO_REQ = 0x0ec,
+ XMM7360_RPC_CALL_UTA_MS_NET_DETACH_REQ = 0x0ef,
+ XMM7360_RPC_CALL_UTA_MS_NET_SELECT_GPRS_CLASS_REQ = 0x0f1,
+ XMM7360_RPC_CALL_UTA_MS_NET_GET_CSG_CONFIG_REQ = 0x0f3,
+ XMM7360_RPC_CALL_UTA_MS_NET_CS_SERVICE_NOTIFICATION_ACCEPT = 0x0f4,
+ XMM7360_RPC_CALL_UTA_MS_NET_SINGLE_SHOT_FD_REQ = 0x0f9,
+ XMM7360_RPC_CALL_UTA_MS_SIM_PB_LOCATION_REQ = 0x0fb,
+ XMM7360_RPC_CALL_UTA_MS_SIM_PB_READ_GAS_ENTRY_REQ = 0x0fd,
+ XMM7360_RPC_CALL_UTA_MS_SIM_PB_WRITE_ENTRY_REQ = 0x0ff,
+ XMM7360_RPC_CALL_UTA_MS_SIM_PB_GET_META_INFORMATION_REQ = 0x101,
+ XMM7360_RPC_CALL_UTA_MS_SIM_PB_USIM_PB_SELECT_REQ = 0x103,
+ XMM7360_RPC_CALL_UTA_MS_SIM_PB_GET_FREE_RECORDS_REQ = 0x105,
+ XMM7360_RPC_CALL_UTA_MS_SIM_CREATE_READ_BINARY_APDU = 0x10a,
+ XMM7360_RPC_CALL_UTA_MS_SIM_CREATE_UPDATE_BINARY_APDU = 0x10b,
+ XMM7360_RPC_CALL_UTA_MS_SIM_ANALYSE_READ_RESULT = 0x10c,
+ XMM7360_RPC_CALL_UTA_MS_SIM_SET_FDN_REQ = 0x10e,
+ XMM7360_RPC_CALL_SET_AP_SCREEN_STATE = 0x110,
+ XMM7360_RPC_CALL_UTA_IO_CTL = 0x111,
+ XMM7360_RPC_CALL_UTA_IDC_AP_MSG_SET_REQ = 0x114,
+ XMM7360_RPC_CALL_UTA_IDC_AP_MSG_GET_REQ = 0x115,
+ XMM7360_RPC_CALL_UTA_IDC_ENBLE_REQ = 0x116,
+ XMM7360_RPC_CALL_UTA_IDC_CWS_MSG_SET_REQ = 0x119,
+ XMM7360_RPC_CALL_UTA_IDC_CWS_MSG_GET_REQ = 0x11a,
+ XMM7360_RPC_CALL_UTA_IDC_SUBSCRIBE_INDICATIONS = 0x11c,
+ XMM7360_RPC_CALL_UTA_IDC_UNSUBSCRIBE_INDICATIONS = 0x11d,
+ XMM7360_RPC_CALL_UTA_BOOT_PREPARE_SHUTDOWN_REQ = 0x11f,
+ XMM7360_RPC_CALL_UTA_BOOT_SHUTDOWN_REQ = 0x120,
+ XMM7360_RPC_CALL_UTA_RF_MAX_TX_PWR_SET_2G = 0x121,
+ XMM7360_RPC_CALL_UTA_RF_MAX_TX_PWR_SET_3G = 0x122,
+ XMM7360_RPC_CALL_UTA_RF_MAX_TX_PWR_SET_4G = 0x123,
+ XMM7360_RPC_CALL_UTA_FREQ_INFO_ACTIVATE_REQ = 0x128,
+ XMM7360_RPC_CALL_UTA_FREQ_INFO_GET_FREQ_INFO_REQ = 0x129,
+ XMM7360_RPC_CALL_UTA_FREQ_INFO_DEACTIVATE_REQ = 0x12a,
+ XMM7360_RPC_CALL_UTA_FREQ_INFO_REGISTER_INDICATIONS = 0x12b,
+ XMM7360_RPC_CALL_UTA_FREQ_INFO_DEREGISTER_INDICATIONS = 0x12c,
+ XMM7360_RPC_CALL_UTA_MODE_SET_REQ = 0x12f,
+ XMM7360_RPC_CALL_UTA_NVM_FLUSH_SYNC = 0x130,
+ XMM7360_RPC_CALL_UTA_PROD_REGISTER_GTI_CALLBACK_FUNC = 0x132,
+ XMM7360_RPC_CALL_UTA_PROD_GTI_CMD_REQ = 0x133,
+ XMM7360_RPC_CALL_UTA_CELL_TIME_STAMP_REQ = 0x134,
+ XMM7360_RPC_CALL_UTA_MS_SS_LCS_INIT = 0x136,
+ XMM7360_RPC_CALL_UTA_MS_SS_LCS_MO_LOCATION_REQ = 0x137,
+ XMM7360_RPC_CALL_UTA_MS_SS_LCS_MTLR_NOTIFICATION_RSP = 0x139,
+ XMM7360_RPC_CALL_UTA_MS_CP_ASSISTANCE_DATA_INJECT_REQ = 0x13c,
+ XMM7360_RPC_CALL_UTA_MS_CP_RESET_ASSISTANCE_DATA = 0x13d,
+ XMM7360_RPC_CALL_UTA_MS_CP_POS_MEASUREMENT_REQ = 0x140,
+ XMM7360_RPC_CALL_UTA_MS_CP_POS_MEASUREMENT_ABORT_REQ = 0x142,
+ XMM7360_RPC_CALL_UTA_MS_CP_POS_ENABLE_MEASUREMENT_REPORT = 0x144,
+ XMM7360_RPC_CALL_UTA_MS_CP_POS_DISABLE_MEASUREMENT_REPORT = 0x145,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_INIT = 0x146,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_EXEC_SMS_PP_RSP = 0x148,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_EXEC_SIM_INITIATED_CALL_RSP = 0x14a,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_EXEC_SS_USSD_RSP = 0x14c,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_EXEC_DTMF_RSP = 0x14e,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_STOP_DTMF_REQ = 0x150,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_REFRESH_CONFIRM_RSP = 0x152,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_REFRESH_FCN_RSP = 0x154,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_CONTROL_REQ = 0x155,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_TERMINAL_PROFILE_DOWNLOAD_REQ = 0x157,
+ XMM7360_RPC_CALL_UTA_MS_3GPP2_SMS_SEND_REQ = 0x15a,
+ XMM7360_RPC_CALL_UTA_MS_3GPP2_SMS_SUBSCRIBE_INDICATIONS = 0x15c,
+ XMM7360_RPC_CALL_UTA_MS_3GPP2_SMS_UNSUBSCRIBE_INDICATIONS = 0x15d,
+ XMM7360_RPC_CALL_RPC_GET_REMOTE_VER_INFO = 0x15e,
+ XMM7360_RPC_CALL_UTA_MS_METRICS_REGISTER_HANDLER = 0x160,
+ XMM7360_RPC_CALL_UTA_MS_METRICS_DEREGISTER_HANDLER = 0x161,
+ XMM7360_RPC_CALL_UTA_MS_METRICS_SET_OPTIONS = 0x162,
+ XMM7360_RPC_CALL_UTA_MS_METRICS_TRIGGER = 0x163,
+ XMM7360_RPC_CALL_UTA_MS_EMBMS_INIT = 0x164,
+ XMM7360_RPC_CALL_UTA_MS_EMBMS_SET_SERVICE_REQ = 0x165,
+ XMM7360_RPC_CALL_UTA_MS_EMBMS_MBSFN_AREA_CONFIG_REQ = 0x166,
+ XMM7360_RPC_CALL_UTA_MS_EMBMS_SESSION_CONFIG_REQ = 0x167,
+ XMM7360_RPC_CALL_UTA_MS_EMBMS_SET_INTERESTED_TMGI_LIST_REQ = 0x168,
+ XMM7360_RPC_CALL_UTA_MS_EMBMS_SET_INTERESTED_SAI_FREQ_REQ = 0x169,
+ XMM7360_RPC_CALL_UTA_IMS_SUBSCRIBE_INDICATIONS = 0x176,
+ XMM7360_RPC_CALL_UTA_IMS_UNSUBSCRIBE_INDICATIONS = 0x177,
+ XMM7360_RPC_CALL_UTA_IMS_GET_FRAMEWORK_STATE = 0x178,
+ XMM7360_RPC_CALL_UTA_RTC_GET_DATETIME = 0x179,
+ XMM7360_RPC_CALL_UTA_MS_SIM_ANALYSE_SIM_APDU_RESULT = 0x17a,
+ XMM7360_RPC_CALL_UTA_MS_SIM_OPEN_CHANNEL_REQ = 0x17b,
+ XMM7360_RPC_CALL_UTA_MS_SIM_CLOSE_CHANNEL_REQ = 0x17d,
+ XMM7360_RPC_CALL_UTA_MS_SIM_SET_BDN_REQ = 0x17f,
+ XMM7360_RPC_CALL_UTA_MS_SET_SIM_STACK_MAPPING_REQ = 0x181,
+ XMM7360_RPC_CALL_UTA_MS_GET_SIM_STACK_MAPPING_REQ = 0x183,
+ XMM7360_RPC_CALL_UTA_MS_NET_SET_RADIO_SIGNAL_REPORTING_CONFIGURATION = 0x188,
+ XMM7360_RPC_CALL_UTA_PC_IE_ENUMERATIONEXT_TOUT = 0x189,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_SET_TERMINAL_CAPABILITY_REQ = 0x18a,
+ XMM7360_RPC_CALL_UTA_MS_SIM_TK_READ_TERMINAL_CAPABILITY_REQ = 0x18c,
+ XMM7360_RPC_CALL_CSI_FCC_LOCK_QUERY_REQ = 0x18e,
+ XMM7360_RPC_CALL_CSI_FCC_LOCK_GEN_CHALLENGE_REQ = 0x190,
+ XMM7360_RPC_CALL_CSI_FCC_LOCK_VER_CHALLENGE_REQ = 0x192,
+ XMM7360_RPC_CALL_UTA_SENSOR_OPEN_REQ = 0x194,
+ XMM7360_RPC_CALL_UTA_SENSOR_CLOSE_EXT = 0x197,
+ XMM7360_RPC_CALL_UTA_SENSOR_START_EXT = 0x198,
+ XMM7360_RPC_CALL_UTA_SENSOR_SET_ALARM_PARAM_EXT = 0x199,
+ XMM7360_RPC_CALL_UTA_SENSOR_SET_SCHEDULER_PARAM_EXT = 0x19a,
+ XMM7360_RPC_CALL_CSI_SIO_IP_FILTER_CNTRL_SET_REQ = 0x19b,
+ XMM7360_RPC_CALL_UTA_MS_ACC_CURRENT_FREQ_INFO_REQ = 0x19d,
+ XMM7360_RPC_CALL_CSI_TRC_AT_CMND_REQ = 0x1a0,
+ XMM7360_RPC_CALL_UTA_MS_SIM_APDU_CMD_EXT_REQ = 0x1a2,
+ XMM7360_RPC_CALL_UTA_MS_NET_GET_PLMN_NAME_INFO_REQ = 0x1a4,
+ XMM7360_RPC_CALL_UTA_MS_NET_GET_COUNTRY_LIST_REQ = 0x1a7,
+ XMM7360_RPC_CALL_UTA_MS_NET_EXT_CONFIGURE_NETWORK_MODE_REQ = 0x1a9,
+ XMM7360_RPC_CALL_UTA_MS_NET_EXT_BAND_STATUS_REQ = 0x1ac,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_ATTACH_APN_CONFIG_REQ = 0x1af,
+ XMM7360_RPC_CALL_CSI_MS_CALL_PS_INITIALIZE = 0x1b1,
+ XMM7360_RPC_CALL_UTA_AUDIO_ENABLE_SOURCE = 0x1b2,
+ XMM7360_RPC_CALL_UTA_AUDIO_DISABLE_SOURCE = 0x1b3,
+ XMM7360_RPC_CALL_UTA_AUDIO_CONFIGURE_DESTINATION_EXT = 0x1b4,
+ XMM7360_RPC_CALL_UTA_AUDIO_SET_DESTINATIONS_FOR_SOURCE = 0x1b5,
+ XMM7360_RPC_CALL_UTA_AUDIO_SET_VOLUME_FOR_SOURCE = 0x1b6,
+ XMM7360_RPC_CALL_UTA_AUDIO_SET_MUTE_FOR_SOURCE_EXT = 0x1b7,
+ XMM7360_RPC_CALL_UTA_AUDIO_SET_VOLUME_FOR_DESTINATION = 0x1b8,
+ XMM7360_RPC_CALL_UTA_AUDIO_SET_MUTE_FOR_DESTINATION_EXT = 0x1b9,
+ XMM7360_RPC_CALL_UTA_AUDIO_CONFIGURE_SOURCE_EXT = 0x1ba,
+ XMM7360_RPC_CALL_UTA_AUDIO_SET_DESTINATIONS_FOR_SOURCE_EXT = 0x1bb,
+ XMM7360_RPC_CALL_UTA_RPC_SCREEN_CONTROL_REQ = 0x1bc,
+ XMM7360_RPC_CALL_UTA_MS_CALL_PS_READ_CONTEXT_STATUS_REQ = 0x1bd,
+ XMM7360_RPC_CALL_CSI_MS_SIM_ACCESS_GET_SIM_STATE_INFO_REQ = 0x1bf,
+ XMM7360_RPC_CALL_CSI_MS_NET_GET_REGISTRATION_INFO_REQ = 0x1c1,
+ XMM7360_RPC_CALL_CSI_SIO_IP_FILTER_NEW_CNTRL_SET_REQ = 0x1c3,
+ XMM7360_RPC_CALL_CSI_MS_NET_LDR_GET_APN_PLMN_PARAMETER_LIST_REQ = 0x1c5,
+ XMM7360_RPC_CALL_RPC_GET_API_PARAM_CHANGED_BITMAP = 0x1c8,
+} Xmm7360RpcCallId;
+
+typedef enum {
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_APDU_CMD_RSP_CB = 0x003,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_APPLICATION_RSP_CB = 0x005,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_INFO_IND_CB = 0x007,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_INIT_IND_CB = 0x008,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_FULL_ACCESS_IND_CB = 0x009,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_ERROR_IND_CB = 0x00a,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_CARD_IND_CB = 0x00b,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_APPLICATION_IND_CB = 0x00c,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_PB_READ_ENTRY_RSP_CB = 0x00e,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_GEN_PIN_RSP_CB = 0x010,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_MODIFY_LOCK_RSP_CB = 0x012,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_LOCK_STATUS_IND_CB = 0x013,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_MO_SMS_CONTROL_INFO_IND_CB = 0x014,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_PROACTIVE_COMMAND_IND_CB = 0x015,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_ENVELOPE_RES_IND_CB = 0x018,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_TERMINAL_PROFILE_READ_RSP_CB = 0x01a,
+ XMM7360_RPC_UNSOL_UTA_SIM_TK_PROACTIVE_COMMAND_HANDLER_FUNC = 0x01b,
+ XMM7360_RPC_UNSOL_UTA_MS_CPS_SET_MODE_RSP = 0x01e,
+ XMM7360_RPC_UNSOL_UTA_MS_CPS_SET_MODE_IND_CB = 0x022,
+ XMM7360_RPC_UNSOL_UTA_MS_SS_NETWORK_ERROR_IND_CB = 0x02a,
+ XMM7360_RPC_UNSOL_UTA_MS_SS_NETWORK_REJECT_IND_CB = 0x02b,
+ XMM7360_RPC_UNSOL_UTA_MS_SS_NETWORK_GSM_CAUSE_IND_CB = 0x02c,
+ XMM7360_RPC_UNSOL_UTA_MS_SS_USSD_RSP_CB = 0x02d,
+ XMM7360_RPC_UNSOL_UTA_MS_SS_USSD_IND_CB = 0x02e,
+ XMM7360_RPC_UNSOL_UTA_MS_SS_END_IND_CB = 0x02f,
+ XMM7360_RPC_UNSOL_UTA_MS_SMS_INCOMING_IND_CB = 0x032,
+ XMM7360_RPC_UNSOL_UTA_MS_SMS_SEND_RSP_CB = 0x033,
+ XMM7360_RPC_UNSOL_UTA_MS_SMS_SET_MEMORY_AVAILABLE_RSP_CB = 0x035,
+ XMM7360_RPC_UNSOL_UTA_MS_SMS_SIM_MSG_CACHE_FINISHED_IND_CB = 0x037,
+ XMM7360_RPC_UNSOL_UTA_MS_SMS_SIM_MSG_COUNT_RSP_CB = 0x039,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_DEFINE_PRIMARY_RSP_CB = 0x03e,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_UNDEFINE_PRIMARY_RSP_CB = 0x040,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_GET_PRIMARY_RSP_CB = 0x042,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_SET_AUTHENTICATION_RSP_CB = 0x044,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_SET_DNS_RSP_CB = 0x046,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_GET_NEGOTIATED_DNS_RSP_CB = 0x048,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_GET_NEG_IP_ADDR_RSP_CB = 0x04a,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_ACTIVATE_RSP_CB = 0x04c,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_ACTIVATE_STATUS_IND_CB = 0x04d,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_DEACTIVATE_RSP_CB = 0x04f,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_DEACTIVATE_IND_CB = 0x050,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_CONNECT_RSP_CB = 0x052,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_SINGLE_SHOT_RADIO_SIGNAL_REPORTING_RSP_CB = 0x056,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_CELL_INFO_IND_CB = 0x057,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_CONNECTION_INFO_IND_CB = 0x058,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_HSPA_INFO_IND_CB = 0x059,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_RADIO_SIGNAL_IND_CB = 0x05a,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_CELL_CHANGE_IND_CB = 0x05b,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_ATTACH_RSP_CB = 0x063,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_PS_ATTACH_RSP_CB = 0x064,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_PS_DETACH_RSP_CB = 0x065,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_SCAN_RSP_CB = 0x066,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_POWER_DOWN_RSP_CB = 0x067,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_EXT_SCAN_RSP_CB = 0x068,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_PS_ATTACH_IND_CB = 0x069,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_PS_DETACH_IND_CB = 0x06a,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_REGISTRATION_INFO_IND_CB = 0x06b,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_IS_ATTACH_ALLOWED_IND_CB = 0x06c,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_GPRS_CLASS_IND_CB = 0x06d,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_SET_FD_CONFIG_RSP_CB = 0x06f,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_FD_CONFIG_IND_CB = 0x070,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_GET_FD_CONFIG_RSP_CB = 0x072,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_CONFIGURE_NETWORK_MODE_RSP_CB = 0x074,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_NETWORK_MODE_CHANGE_IND_CB = 0x075,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_RAT_MODE_STATUS_RSP_CB = 0x077,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_RAT_MODE_STATUS_IND_CB = 0x078,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_DC_SET_VOICE_DOMAIN_PREFERENCE_CONFIG_RSP_CB = 0x081,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_SETUP_CALL_RSP_CB = 0x083,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_DIALING_IND_CB = 0x084,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_ALERTING_IND_CB = 0x085,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_CTM_INFO_IND_CB = 0x086,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_CONNECTED_IND_CB = 0x087,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_RELEASE_CALL_RSP_CB = 0x089,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_DISCONNECTING_IND_CB = 0x08a,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_DISCONNECTED_IND_CB = 0x08b,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_INCOMING_CALL_IND_CB = 0x08c,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_ACCEPT_CALL_RSP_CB = 0x08e,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_PROGRESS_IND_CB = 0x08f,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_SWAP_CALLS_RSP_CB = 0x091,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_HOLD_CALL_RSP_CB = 0x093,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_RETRIEVE_CALL_RSP_CB = 0x095,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_SPLIT_MPTY_RSP_CB = 0x097,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_JOIN_CALLS_RSP_CB = 0x099,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_TRANSFER_CALLS_RSP_CB = 0x09b,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_START_DTMF_RSP_CB = 0x09d,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_STOP_DTMF_RSP_CB = 0x09f,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_STOP_DTMF_EXT_RSP_CB = 0x0a0,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_NOTIFICATION_IND_CB = 0x0a1,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_CUG_INFO_IND_CB = 0x0a2,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_CALLING_NAME_INFO_IND_CB = 0x0a3,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_EMERGENCY_NUMBER_LIST_IND_CB = 0x0a4,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_CALL_STATUS_IND_CB = 0x0a5,
+ XMM7360_RPC_UNSOL_UTA_CALL_MULTIMEDIA_GET_MEDIA_PROFILES_INFO_RSP_CB = 0x0a9,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_MULTIMEDIA_SETUP_CALL_RSP_CB = 0x0aa,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_MULTIMEDIA_UPDATE_CALL_RSP_CB = 0x0ab,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_CS_VOIMS_SRVCC_HO_STATUS_IND_CB = 0x0ae,
+ XMM7360_RPC_UNSOL_UTA_MS_CPS_SET_SIM_MODE_RSP = 0x0af,
+ XMM7360_RPC_UNSOL_UTA_MS_CPS_STARTUP_IND_CB = 0x0b1,
+ XMM7360_RPC_UNSOL_UTA_MS_SS_CALL_FORWARD_RSP_CB = 0x0b3,
+ XMM7360_RPC_UNSOL_UTA_MS_SS_CALL_WAITING_RSP_CB = 0x0b5,
+ XMM7360_RPC_UNSOL_UTA_MS_SS_CALL_BARRING_RSP_CB = 0x0b7,
+ XMM7360_RPC_UNSOL_UTA_MS_SS_IDENTIFICATION_RSP_CB = 0x0b9,
+ XMM7360_RPC_UNSOL_UTA_MS_SMS_DATA_DOWNLOAD_RSP_CB = 0x0bc,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_GET_NEG_QOS_RSP_CB = 0x0bf,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_GET_TFT_RSP_CB = 0x0c1,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_SET_PCO_RSP_CB = 0x0c3,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_GET_NW_PCO_RSP_CB = 0x0c5,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_NW_ACTIVATE_IND_CB = 0x0c6,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_NW_ACTIVATE_ACCEPT_RSP_CB = 0x0c8,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_MODIFY_IND_CB = 0x0ca,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_SUSPEND_IND_CB = 0x0cb,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_RESUME_IND_CB = 0x0cc,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_SET_DATA_PREF_RSP_CB = 0x0ce,
+ XMM7360_RPC_UNSOL_UTA_MS_CBS_START_RSP_CB = 0x0d1,
+ XMM7360_RPC_UNSOL_UTA_MS_CBS_STOP_RSP_CB = 0x0d2,
+ XMM7360_RPC_UNSOL_UTA_MS_CBS_NEW_MESSAGE_IND_CB = 0x0d5,
+ XMM7360_RPC_UNSOL_UTA_MS_CBS_ETWS_CONFIG_RSP_CB = 0x0d7,
+ XMM7360_RPC_UNSOL_UTA_MS_CBS_ETWS_START_RSP_CB = 0x0d9,
+ XMM7360_RPC_UNSOL_UTA_MS_CBS_ETWS_STOP_RSP_CB = 0x0db,
+ XMM7360_RPC_UNSOL_UTA_MS_CBS_ETWS_NOTIFY_PRIMARY_WARNING_IND = 0x0dc,
+ XMM7360_RPC_UNSOL_UTA_MS_CBS_ETWS_NOTIFY_SECONDARY_WARNING_IND = 0x0dd,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_CONFIGURE_RX_DIVERSITY_DARP_IND_CB = 0x0e1,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_TIME_INFO_READ_RSP_CB = 0x0e4,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_TIME_INFO_IND_CB = 0x0e5,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_BAND_STATUS_RSP_CB = 0x0e8,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_BAND_STATUS_IND_CB = 0x0e9,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_SET_CSG_CONFIG_RSP_CB = 0x0ea,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_GET_CSG_CONFIG_RSP_CB = 0x0eb,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_GET_EXTENDED_RADIO_SIGNAL_INFO_RSP_CB = 0x0ed,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_NITZ_INFO_IND_CB = 0x0ee,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_DETACH_RSP_CB = 0x0f0,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_SELECT_GPRS_CLASS_RSP_CB = 0x0f2,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_NETWORK_FEATURE_SUPPORT_INFO_IND_CB = 0x0f5,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_EPS_NETWORK_FEATURE_SUPPORT_INFO_IND_CB = 0x0f6,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_CS_SERVICE_NOTIFICATION_IND_CB = 0x0f7,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_DUAL_SIM_SERVICE_IND_CB = 0x0f8,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_SINGLE_SHOT_FD_RSP_CB = 0x0fa,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_PB_GET_LOCATION_RSP_CB = 0x0fc,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_PB_READ_GAS_ENTRY_RSP_CB = 0x0fe,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_PB_WRITE_ENTRY_RSP_CB = 0x100,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_PB_GET_META_INFORMATION_RSP_CB = 0x102,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_PB_USIM_PB_SELECT_RSP_CB = 0x104,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_PB_GET_FREE_RECORDS_RSP_CB = 0x106,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_PB_USIM_PB_READY_IND_CB = 0x107,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_PB_CACHE_LOAD_FINISHED_IND_CB = 0x108,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_PB_CACHE_LOAD_IND_CB = 0x109,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_GEN_PIN_IND_CB = 0x10d,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_FDN_STATE_IND_CB = 0x10f,
+ XMM7360_RPC_UNSOL_UTA_IDC_AP_MSG_SET_RSP_CB = 0x112,
+ XMM7360_RPC_UNSOL_UTA_IDC_AP_MSG_GET_RSP_CB = 0x113,
+ XMM7360_RPC_UNSOL_UTA_IDC_CWS_MSG_SET_RSP_CB = 0x117,
+ XMM7360_RPC_UNSOL_UTA_IDC_CWS_MSG_GET_RSP_CB = 0x118,
+ XMM7360_RPC_UNSOL_UTA_IDC_CWS_MSG_IND_CB = 0x11b,
+ XMM7360_RPC_UNSOL_UTA_BOOT_PREPARE_SHUTDOWN_RSP_CB = 0x11e,
+ XMM7360_RPC_UNSOL_UTA_FREQ_INFO_ACTIVATE_RSP_CB = 0x124,
+ XMM7360_RPC_UNSOL_UTA_FREQ_INFO_DEACTIVATE_RSP_CB = 0x125,
+ XMM7360_RPC_UNSOL_UTA_FREQ_INFO_GET_FREQ_INFO_RSP_CB = 0x126,
+ XMM7360_RPC_UNSOL_UTA_FREQ_INFO_INDICATION_CB = 0x127,
+ XMM7360_RPC_UNSOL_UTA_MODE_SET_RSP_CB = 0x12d,
+ XMM7360_RPC_UNSOL_UTA_MODE_STARTUP_IND_CB = 0x12e,
+ XMM7360_RPC_UNSOL_UTA_PROD_GTI_CMD_RSP_CB = 0x131,
+ XMM7360_RPC_UNSOL_UTA_CELL_TIME_STAMP_RSP_CB = 0x135,
+ XMM7360_RPC_UNSOL_UTA_MS_SS_LCS_MO_LOCATION_RSP_CB = 0x138,
+ XMM7360_RPC_UNSOL_UTA_MS_SS_LCS_CAPABILITIES_IND_CB = 0x13a,
+ XMM7360_RPC_UNSOL_UTA_MS_CP_ASSISTANCE_DATA_INJECT_RSP_CB = 0x13b,
+ XMM7360_RPC_UNSOL_UTA_MS_CP_ASSISTANCE_DATA_NEEDED_IND_CB = 0x13e,
+ XMM7360_RPC_UNSOL_UTA_MS_CP_POS_MEASUREMENT_RSP_CB = 0x13f,
+ XMM7360_RPC_UNSOL_UTA_MS_CP_POS_MEASUREMENT_ABORT_RSP_CB = 0x141,
+ XMM7360_RPC_UNSOL_UTA_MS_CP_POS_REPORT_MEASUREMENT_IND_CB = 0x143,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_EXEC_SMS_PP_IND_CB = 0x147,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_EXEC_SIM_INITIATED_CALL_IND_CB = 0x149,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_EXEC_SS_USSD_IND_CB = 0x14b,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_EXEC_DTMF_IND_CB = 0x14d,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_EXEC_DTMF_END_IND_CB = 0x14f,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_REFRESH_CONFIRM_IND_CB = 0x151,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_REFRESH_FCN_IND_CB = 0x153,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_CONTROL_RSP_CB = 0x156,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_TERMINAL_PROFILE_DOWNLOAD_RSP_CB = 0x158,
+ XMM7360_RPC_UNSOL_UTA_MS_3GPP2_SMS_SEND_RSP_CB = 0x159,
+ XMM7360_RPC_UNSOL_UTA_MS_3GPP2_SMS_INCOMING_IND_CB = 0x15b,
+ XMM7360_RPC_UNSOL_UTA_METRICS_HANDLER_FUNCTION = 0x15f,
+ XMM7360_RPC_UNSOL_UTA_MS_EMBMS_SET_SERVICE_RSP_CB = 0x16a,
+ XMM7360_RPC_UNSOL_UTA_MS_EMBMS_MBSFN_AREA_CONFIG_RSP_CB = 0x16b,
+ XMM7360_RPC_UNSOL_UTA_MS_EMBMS_SESSION_CONFIG_RSP_CB = 0x16c,
+ XMM7360_RPC_UNSOL_UTA_MS_EMBMS_SET_INTERESTED_TMGI_LIST_RSP_CB = 0x16d,
+ XMM7360_RPC_UNSOL_UTA_MS_EMBMS_SET_INTERESTED_SAI_FREQ_RSP_CB = 0x16e,
+ XMM7360_RPC_UNSOL_UTA_MS_EMBMS_SERVICE_IND_CB = 0x16f,
+ XMM7360_RPC_UNSOL_UTA_MS_EMBMS_MBSFN_AREA_IND_CB = 0x170,
+ XMM7360_RPC_UNSOL_UTA_MS_EMBMS_SERVICES_LIST_IND_CB = 0x171,
+ XMM7360_RPC_UNSOL_UTA_MS_EMBMS_SAI_LIST_IND_CB = 0x172,
+ XMM7360_RPC_UNSOL_UTA_MS_EMBMS_MPS_INFO_IND_CB = 0x173,
+ XMM7360_RPC_UNSOL_UTA_IMS_STATE_CHANGED_IND_CB = 0x174,
+ XMM7360_RPC_UNSOL_UTA_IMS_SERVICE_STATE_CHANGED_IND_CB = 0x175,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_OPEN_CHANNEL_RSP_CB = 0x17c,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_CLOSE_CHANNEL_RSP_CB = 0x17e,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_BDN_STATE_IND_CB = 0x180,
+ XMM7360_RPC_UNSOL_UTA_MS_SET_SIM_STACK_MAPPING_RSP_CB = 0x182,
+ XMM7360_RPC_UNSOL_UTA_MS_GET_SIM_STACK_MAPPING_RSP_CB = 0x184,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_MCC_MNC_IND_CB = 0x185,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_TERMINAL_RESPONSE_IND_CB = 0x186,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_REGISTERED_PLMN_NAME_IND_CB = 0x187,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_SET_TERMINAL_CAPABILITY_RSP_CB = 0x18b,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_TK_READ_TERMINAL_CAPABILITY_RSP_CB = 0x18d,
+ XMM7360_RPC_UNSOL_CSI_FCC_LOCK_QUERY_RSP_CB = 0x18f,
+ XMM7360_RPC_UNSOL_CSI_FCC_LOCK_GEN_CHALLENGE_RSP_CB = 0x191,
+ XMM7360_RPC_UNSOL_CSI_FCC_LOCK_VER_CHALLENGE_RSP_CB = 0x193,
+ XMM7360_RPC_UNSOL_UTA_SENSOR_OPEN_RSP_CB = 0x195,
+ XMM7360_RPC_UNSOL_UTA_SENSOR_MEAS_IND_CB = 0x196,
+ XMM7360_RPC_UNSOL_CSI_SIO_IP_FILTER_CNTRL_SET_RSP_CB = 0x19c,
+ XMM7360_RPC_UNSOL_CSI_SIO_IP_FILTER_NEW_CNTRL_SET_RSP_CB = 0x1c4,
+ XMM7360_RPC_UNSOL_UTA_MS_ACC_CURRENT_FREQ_INFO_RSP_CB = 0x19e,
+ XMM7360_RPC_UNSOL_UTA_MS_ACC_CURRENT_FREQ_INFO_IND_CB = 0x19f,
+ XMM7360_RPC_UNSOL_CSI_TRC_AT_CMND_RSP_CB = 0x1a1,
+ XMM7360_RPC_UNSOL_UTA_MS_SIM_APDU_CMD_EXT_RSP_CB = 0x1a3,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_GET_PLMN_NAME_INFO_RSP_CB = 0x1a5,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_SIB8_TIME_INFO_IND_CB = 0x1a6,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_GET_COUNTRY_LIST_RSP_CB = 0x1a8,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_EXT_CONFIGURE_NETWORK_MODE_RSP_CB = 0x1aa,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_EXT_NETWORK_MODE_CHANGE_IND_CB = 0x1ab,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_EXT_BAND_STATUS_RSP_CB = 0x1ad,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_EXT_BAND_STATUS_IND_CB = 0x1ae,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_ATTACH_APN_CONFIG_RSP_CB = 0x1b0,
+ XMM7360_RPC_UNSOL_UTA_MS_CALL_PS_READ_CONTEXT_STATUS_RSP_CB = 0x1be,
+ XMM7360_RPC_UNSOL_CSI_MS_SIM_ACCESS_GET_SIM_STATE_INFO_RSP_CB = 0x1c0,
+ XMM7360_RPC_UNSOL_CSI_MS_NET_GET_REGISTRATION_INFO_RSP_CB = 0x1c2,
+ XMM7360_RPC_UNSOL_CSI_MS_NET_LDR_GET_APN_PLMN_PARAMETER_LIST_RSP_CB = 0x1c6,
+ XMM7360_RPC_UNSOL_UTA_MS_NET_LDR_APN_PARAMETERS_CHANGE_IND_CB = 0x1c7,
+} Xmm7360RpcUnsolId;
+
+typedef enum {
+ XMM7360_RPC_MSG_ARG_TYPE_BYTE,
+ XMM7360_RPC_MSG_ARG_TYPE_SHORT,
+ XMM7360_RPC_MSG_ARG_TYPE_LONG,
+ XMM7360_RPC_MSG_ARG_TYPE_STRING,
+ XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN,
+} Xmm7360RpcMsgArgType;
+
+
+#define XMM7360_RPC_MSG_ARG_GET_INT(arg) \
+ (arg->type == XMM7360_RPC_MSG_ARG_TYPE_BYTE ? arg->value.b \
+ : arg->type == XMM7360_RPC_MSG_ARG_TYPE_SHORT ? arg->value.s \
+ : arg->type == XMM7360_RPC_MSG_ARG_TYPE_LONG ? arg->value.l : -1)
+
+typedef struct {
+ Xmm7360RpcMsgArgType type;
+ union {
+ gint8 b;
+ gint16 s;
+ gint32 l;
+ const gchar *string;
+ } value;
+ gsize size;
+ gsize pad;
+} Xmm7360RpcMsgArg;
+
+typedef enum {
+ XMM7360_RPC_RESPONSE_TYPE_RESPONSE,
+ XMM7360_RPC_RESPONSE_TYPE_ASYNC_ACK,
+ XMM7360_RPC_RESPONSE_TYPE_UNSOLICITED,
+ XMM7360_RPC_RESPONSE_TYPE_UNKNOWN,
+} Xmm7360RpcResponseType;
+
+typedef struct {
+ guint32 id;
+ Xmm7360RpcResponseType type;
+ guint32 unsol_id;
+ GByteArray *body;
+ GPtrArray *content; /* contains (Xmm7360RpcMsgArgs *) */
+} Xmm7360RpcResponse;
+
+#define MM_TYPE_PORT_SERIAL_XMMRPC_XMM7360 (mm_port_serial_xmmrpc_xmm7360_get_type ())
+#define MM_PORT_SERIAL_XMMRPC_XMM7360(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PORT_SERIAL_XMMRPC_XMM7360, MMPortSerialXmmrpcXmm7360))
+#define MM_PORT_SERIAL_XMMRPC_XMM7360_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PORT_SERIAL_XMMRPC_XMM7360, MMPortSerialXmmrpcXmm7360Class))
+#define MM_IS_PORT_SERIAL_XMMRPC_XMM7360(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PORT_SERIAL_XMMRPC_XMM7360))
+#define MM_IS_PORT_SERIAL_XMMRPC_XMM7360_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PORT_SERIAL_XMMRPC_XMM7360))
+#define MM_PORT_SERIAL_XMMRPC_XMM7360_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PORT_SERIAL_XMMRPC_XMM7360, MMPortSerialXmmrpcXmm7360Class))
+
+typedef struct _MMPortSerialXmmrpcXmm7360 MMPortSerialXmmrpcXmm7360;
+typedef struct _MMPortSerialXmmrpcXmm7360Class MMPortSerialXmmrpcXmm7360Class;
+typedef struct _MMPortSerialXmmrpcXmm7360Private MMPortSerialXmmrpcXmm7360Private;
+
+typedef gboolean (*MMPortSerialXmmrpcXmm7360UnsolicitedMsgFn) (MMPortSerialXmmrpcXmm7360 *port,
+ Xmm7360RpcResponse *response,
+ gpointer user_data);
+
+struct _MMPortSerialXmmrpcXmm7360 {
+ MMPortSerial parent;
+ MMPortSerialXmmrpcXmm7360Private *priv;
+};
+
+struct _MMPortSerialXmmrpcXmm7360Class {
+ MMPortSerialClass parent;
+};
+
+GType mm_port_serial_xmmrpc_xmm7360_get_type (void);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMPortSerialXmmrpcXmm7360, g_object_unref)
+
+MMPortSerialXmmrpcXmm7360 *mm_port_serial_xmmrpc_xmm7360_new (const char *name);
+
+void mm_port_serial_xmmrpc_xmm7360_command (MMPortSerialXmmrpcXmm7360 *self,
+ Xmm7360RpcCallId callid,
+ gboolean is_async,
+ GByteArray *body,
+ guint32 timeout_seconds,
+ gboolean allow_cached,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+void xmm7360_byte_array_append_asn_int4 (GByteArray *array, gint32 value);
+
+void xmm7360_rpc_response_free (Xmm7360RpcResponse *msg);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (Xmm7360RpcResponse, xmm7360_rpc_response_free);
+
+GByteArray *xmm7360_rpc_args_to_byte_array (const Xmm7360RpcMsgArg *args);
+
+Xmm7360RpcResponse *mm_port_serial_xmmrpc_xmm7360_command_finish (MMPortSerialXmmrpcXmm7360 *self,
+ GAsyncResult *res,
+ GError **error);
+
+guint mm_port_serial_xmmrpc_xmm7360_add_unsolicited_msg_handler (MMPortSerialXmmrpcXmm7360 *self,
+ MMPortSerialXmmrpcXmm7360UnsolicitedMsgFn callback,
+ gpointer user_data,
+ GDestroyNotify notify);
+
+void mm_port_serial_xmmrpc_xmm7360_enable_unsolicited_msg_handler (MMPortSerialXmmrpcXmm7360 *self,
+ guint handler_id,
+ gboolean enable);
+
+#endif /* MM_PORT_SERIAL_XMMRPC_XMM7360_H */
diff --git a/src/plugins/intel/mm-sim-xmm7360.c b/src/plugins/intel/mm-sim-xmm7360.c
new file mode 100644
index 00000000..912e66e8
--- /dev/null
+++ b/src/plugins/intel/mm-sim-xmm7360.c
@@ -0,0 +1,445 @@
+/* -*- 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 Thomas Vogt
+ */
+
+#include "mm-broadband-modem-xmm7360.h"
+#include "mm-broadband-modem-xmm7360-rpc.h"
+#include "mm-log-object.h"
+#include "mm-sim-xmm7360.h"
+
+G_DEFINE_TYPE (MMSimXmm7360, mm_sim_xmm7360, MM_TYPE_BASE_SIM)
+
+#define PIN_PADDED { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
+#define PIN_PADDED_SIZE 8
+
+static void
+copy_pin (const gchar *pin, gchar *pin_padded)
+{
+ gsize i;
+
+ for (i = 0; pin[i] != 0 && i < PIN_PADDED_SIZE; i++)
+ pin_padded[i] = pin[i];
+}
+
+static void
+update_modem_unlock_retries (MMSimXmm7360 *self,
+ MMModemLock lock_type,
+ guint32 remaining_attempts)
+{
+ g_autoptr(MMBaseModem) modem = NULL;
+
+ g_object_get (G_OBJECT (self),
+ MM_BASE_SIM_MODEM, &modem,
+ NULL);
+ g_assert (MM_IS_BASE_MODEM (modem));
+
+ mm_broadband_modem_xmm7360_set_unlock_retries (MM_BROADBAND_MODEM_XMM7360 (modem),
+ lock_type,
+ remaining_attempts);
+ g_object_unref (modem);
+}
+
+/*****************************************************************************/
+/* Enable PIN */
+
+static gboolean
+enable_pin_finish (MMBaseSim *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+gen_pin_enable_ready (MMBroadbandModem *modem,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMSimXmm7360 *self;
+ GError *error = NULL;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+ Xmm7360RpcMsgArg *arg;
+ guint8 err_code_1;
+ guint8 err_code_2;
+ guint32 remaining_attempts;
+ Xmm7360GenPinOp op;
+ MMModemLock lock_type;
+
+ self = g_task_get_source_object (task);
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (MM_BROADBAND_MODEM_XMM7360 (modem),
+ res,
+ &error);
+
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 2);
+ remaining_attempts = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 3);
+ err_code_1 = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 4);
+ err_code_2 = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 7);
+ op = (Xmm7360GenPinOp) XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ lock_type = remaining_attempts > 0 ? MM_MODEM_LOCK_SIM_PIN : MM_MODEM_LOCK_SIM_PUK;
+ update_modem_unlock_retries (self, lock_type, remaining_attempts);
+
+ if (err_code_1 == 0x83 && err_code_2 == 0x69) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "%s PIN failed (need to unlock PUK first)",
+ op == XMM7360_GEN_PIN_OP_ENABLE ? "Enabling" : "Disabling");
+ g_object_unref (task);
+ return;
+ } else if (err_code_1 == 0x84 && err_code_2 == 0x69) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "%s PIN failed (already %s)",
+ op == XMM7360_GEN_PIN_OP_ENABLE ? "Enabling" : "Disabling",
+ op == XMM7360_GEN_PIN_OP_ENABLE ? "enabled" : "disabled");
+ g_object_unref (task);
+ return;
+ } else if (err_code_2 == 0x63 && (err_code_1 == 0xc2 || err_code_1 == 0xc1 || err_code_1 == 0xc0)) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "%s PIN failed (wrong PIN, %d retries left)",
+ op == XMM7360_GEN_PIN_OP_ENABLE ? "Enabling" : "Disabling",
+ remaining_attempts);
+ g_object_unref (task);
+ return;
+ } else if (err_code_1 != 0x00 || err_code_2 != 0x90) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "%s PIN failed (unknown error: 0x%02x, 0x%02x)",
+ op == XMM7360_GEN_PIN_OP_ENABLE ? "Enabling" : "Disabling",
+ err_code_1, err_code_2);
+ g_object_unref (task);
+ return;
+ }
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static GByteArray *
+padded_pack_gen_pin_enable (const gchar *pin_padded, const Xmm7360GenPinOp op)
+{
+ const Xmm7360RpcMsgArg args[] = {
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = op } },
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 1 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = pin_padded }, 8, 2 },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN },
+ };
+ return xmm7360_rpc_args_to_byte_array (args);
+}
+
+static GByteArray *
+pack_gen_pin_enable (const gchar *pin, gboolean enabled)
+{
+ gchar pin_padded[] = PIN_PADDED;
+ copy_pin (pin, pin_padded);
+ return padded_pack_gen_pin_enable (
+ pin_padded,
+ enabled ? XMM7360_GEN_PIN_OP_ENABLE : XMM7360_GEN_PIN_OP_DISABLE
+ );
+}
+
+static void
+enable_pin (MMBaseSim *self,
+ const gchar *pin,
+ gboolean enabled,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ g_autoptr(MMBaseModem) modem = NULL;
+ MMPortSerialXmmrpcXmm7360 *port;
+ g_autoptr(GByteArray) body = NULL;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ g_object_get (G_OBJECT (self),
+ MM_BASE_SIM_MODEM, &modem,
+ NULL);
+ g_assert (MM_IS_BASE_MODEM (modem));
+
+ port = mm_broadband_modem_xmm7360_peek_port_xmmrpc (MM_BROADBAND_MODEM_XMM7360 (modem));
+ g_object_unref (modem);
+
+ if (!port) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Couldn't peek XMMRPC port");
+ g_object_unref (task);
+ return;
+ }
+
+ body = pack_gen_pin_enable (pin, enabled);
+
+ mm_broadband_modem_xmm7360_rpc_command_full (MM_BROADBAND_MODEM_XMM7360 (modem),
+ port,
+ XMM7360_RPC_CALL_UTA_MS_SIM_GEN_PIN_REQ,
+ TRUE,
+ body,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)gen_pin_enable_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* Change PIN */
+
+static gboolean
+change_pin_finish (MMBaseSim *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+gen_pin_change_ready (MMBroadbandModem *modem,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMSimXmm7360 *self;
+ GError *error = NULL;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+ Xmm7360RpcMsgArg *arg;
+ guint8 err_code_1;
+ guint8 err_code_2;
+ guint32 remaining_attempts;
+ MMModemLock lock_type;
+
+ self = g_task_get_source_object (task);
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (MM_BROADBAND_MODEM_XMM7360 (modem),
+ res,
+ &error);
+
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (response->content->len < 10) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Changing PIN failed (response too short)");
+ g_object_unref (task);
+ return;
+ }
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 2);
+ remaining_attempts = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 3);
+ err_code_1 = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 4);
+ err_code_2 = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ lock_type = remaining_attempts > 0 ? MM_MODEM_LOCK_SIM_PIN : MM_MODEM_LOCK_SIM_PUK;
+ update_modem_unlock_retries (self, lock_type, remaining_attempts);
+
+ if (err_code_1 == 0x83 && err_code_2 == 0x69) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Changing PIN failed (need to unlock PUK first)");
+ g_object_unref (task);
+ return;
+ } else if (err_code_1 == 0x84 && err_code_2 == 0x69) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Changing PIN failed (PIN lock is disabled)");
+ g_object_unref (task);
+ return;
+ } else if (err_code_2 == 0x63 && (err_code_1 == 0xc2 || err_code_1 == 0xc1 || err_code_1 == 0xc0)) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Changing PIN failed (wrong PIN, %d retries left)",
+ remaining_attempts);
+ g_object_unref (task);
+ return;
+ } else if (err_code_1 != 0x00 || err_code_2 != 0x90) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Changing PIN failed (unknown error: 0x%02x, 0x%02x)",
+ err_code_1, err_code_2);
+ g_object_unref (task);
+ return;
+ }
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static GByteArray *
+padded_pack_gen_pin_change (const gchar *old_pin_padded, const gchar *new_pin_padded)
+{
+ const Xmm7360RpcMsgArg args[] = {
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = XMM7360_GEN_PIN_OP_CHANGE } },
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 1 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = new_pin_padded }, 8, 2},
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = old_pin_padded }, 8, 2},
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN },
+ };
+ return xmm7360_rpc_args_to_byte_array (args);
+}
+
+static GByteArray *
+pack_gen_pin_change (const gchar *old_pin, const gchar *new_pin)
+{
+ gchar old_pin_padded[] = PIN_PADDED;
+ gchar new_pin_padded[] = PIN_PADDED;
+ copy_pin (old_pin, old_pin_padded);
+ copy_pin (new_pin, new_pin_padded);
+ return padded_pack_gen_pin_change (old_pin_padded, new_pin_padded);
+}
+
+static void
+change_pin (MMBaseSim *self,
+ const gchar *old_pin,
+ const gchar *new_pin,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ g_autoptr(MMBaseModem) modem = NULL;
+ MMPortSerialXmmrpcXmm7360 *port;
+ g_autoptr(GByteArray) body = NULL;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ g_object_get (G_OBJECT (self),
+ MM_BASE_SIM_MODEM, &modem,
+ NULL);
+ g_assert (MM_IS_BASE_MODEM (modem));
+
+ port = mm_broadband_modem_xmm7360_peek_port_xmmrpc (MM_BROADBAND_MODEM_XMM7360 (modem));
+ g_object_unref (modem);
+
+ if (!port) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Couldn't peek XMMRPC port");
+ g_object_unref (task);
+ return;
+ }
+
+ body = pack_gen_pin_change (old_pin, new_pin);
+
+ mm_broadband_modem_xmm7360_rpc_command_full (MM_BROADBAND_MODEM_XMM7360 (modem),
+ port,
+ XMM7360_RPC_CALL_UTA_MS_SIM_GEN_PIN_REQ,
+ TRUE,
+ body,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)gen_pin_change_ready,
+ task);
+}
+
+/*****************************************************************************/
+
+MMBaseSim *
+mm_sim_xmm7360_new_finish (GAsyncResult *res,
+ GError **error)
+{
+ GObject *source;
+ GObject *sim;
+
+ source = g_async_result_get_source_object (res);
+ sim = g_async_initable_new_finish (G_ASYNC_INITABLE (source), res, error);
+ g_object_unref (source);
+
+ if (!sim)
+ return NULL;
+
+ /* Only export valid SIMs */
+ mm_base_sim_export (MM_BASE_SIM (sim));
+
+ return MM_BASE_SIM (sim);
+}
+
+void
+mm_sim_xmm7360_new (MMBaseModem *modem,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_async_initable_new_async (MM_TYPE_SIM_XMM7360,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ callback,
+ user_data,
+ MM_BASE_SIM_MODEM, modem,
+ "active", TRUE, /* by default always active */
+ NULL);
+}
+
+MMBaseSim *
+mm_sim_xmm7360_new_initialized (MMBaseModem *modem,
+ guint slot_number,
+ gboolean active,
+ MMSimType sim_type,
+ MMSimEsimStatus esim_status,
+ const gchar *sim_identifier,
+ const gchar *imsi,
+ const gchar *eid,
+ const gchar *operator_identifier,
+ const gchar *operator_name,
+ const GStrv emergency_numbers)
+{
+ MMBaseSim *sim;
+
+ sim = MM_BASE_SIM (g_object_new (MM_TYPE_SIM_XMM7360,
+ MM_BASE_SIM_MODEM, modem,
+ MM_BASE_SIM_SLOT_NUMBER, slot_number,
+ "active", active,
+ "sim-type", sim_type,
+ "esim-status", esim_status,
+ "sim-identifier", sim_identifier,
+ "eid", eid,
+ "operator-identifier", operator_identifier,
+ "operator-name", operator_name,
+ "emergency-numbers", emergency_numbers,
+ NULL));
+
+ mm_base_sim_export (sim);
+ return sim;
+}
+
+static void
+mm_sim_xmm7360_init (MMSimXmm7360 *self)
+{
+}
+
+static void
+mm_sim_xmm7360_class_init (MMSimXmm7360Class *klass)
+{
+ MMBaseSimClass *base_sim_class = MM_BASE_SIM_CLASS (klass);
+
+ base_sim_class->enable_pin = enable_pin;
+ base_sim_class->enable_pin_finish = enable_pin_finish;
+ base_sim_class->change_pin = change_pin;
+ base_sim_class->change_pin_finish = change_pin_finish;
+}
diff --git a/src/plugins/intel/mm-sim-xmm7360.h b/src/plugins/intel/mm-sim-xmm7360.h
new file mode 100644
index 00000000..c83a9fc5
--- /dev/null
+++ b/src/plugins/intel/mm-sim-xmm7360.h
@@ -0,0 +1,68 @@
+/* -*- 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 Thomas Vogt
+ */
+
+#ifndef MM_SIM_XMM7360_H
+#define MM_SIM_XMM7360_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "mm-base-sim.h"
+
+typedef enum {
+ XMM7360_GEN_PIN_OP_DISABLE = 2,
+ XMM7360_GEN_PIN_OP_ENABLE = 3,
+ XMM7360_GEN_PIN_OP_CHANGE = 4,
+} Xmm7360GenPinOp;
+
+#define MM_TYPE_SIM_XMM7360 (mm_sim_xmm7360_get_type ())
+#define MM_SIM_XMM7360(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SIM_XMM7360, MMSimXmm7360))
+#define MM_SIM_XMM7360_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SIM_XMM7360, MMSimXmm7360Class))
+#define MM_IS_SIM_XMM7360(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SIM_XMM7360))
+#define MM_IS_SIM_XMM7360_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SIM_XMM7360))
+#define MM_SIM_XMM7360_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SIM_XMM7360, MMSimXmm7360Class))
+
+typedef struct _MMSimXmm7360 MMSimXmm7360;
+typedef struct _MMSimXmm7360Class MMSimXmm7360Class;
+
+struct _MMSimXmm7360 {
+ MMBaseSim parent;
+};
+
+struct _MMSimXmm7360Class {
+ MMBaseSimClass parent;
+};
+
+GType mm_sim_xmm7360_get_type (void);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSimXmm7360, g_object_unref)
+
+void mm_sim_xmm7360_new (MMBaseModem *modem,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+MMBaseSim *mm_sim_xmm7360_new_finish (GAsyncResult *res,
+ GError **error);
+MMBaseSim *mm_sim_xmm7360_new_initialized (MMBaseModem *modem,
+ guint slot_number,
+ gboolean active,
+ MMSimType sim_type,
+ MMSimEsimStatus esim_status,
+ const gchar *sim_identifier,
+ const gchar *imsi,
+ const gchar *eid,
+ const gchar *operator_identifier,
+ const gchar *operator_name,
+ const GStrv emergency_numbers);
+#endif /* MM_SIM_XMM7360_H */
diff --git a/src/plugins/meson.build b/src/plugins/meson.build
index b21b5e36..b1b6bb22 100644
--- a/src/plugins/meson.build
+++ b/src/plugins/meson.build
@@ -582,8 +582,15 @@ endif
# plugin: intel
if plugins_options['intel']
+ intel_inc = include_directories('intel')
+
sources = files(
'intel/mm-plugin-intel.c',
+ 'intel/mm-broadband-modem-xmm7360.c',
+ 'intel/mm-broadband-modem-xmm7360-rpc.c',
+ 'intel/mm-port-serial-xmmrpc-xmm7360.c',
+ 'intel/mm-bearer-xmm7360.c',
+ 'intel/mm-sim-xmm7360.c',
)
if enable_mbim
@@ -592,9 +599,40 @@ if plugins_options['intel']
common_c_args = '-DMM_MODULE_NAME="intel"'
+ headers = files('intel/mm-port-serial-xmmrpc-xmm7360.h')
+
+ enums_types = 'mm-intel-enums-types'
+
+ sources += custom_target(
+ enums_types + '.c',
+ input: headers,
+ output: enums_types + '.c',
+ command: [
+ python,
+ mm_mkenums,
+ '--fhead', '#include "' + enums_types + '.h"\n',
+ '--template', files(templates_dir / enums_types + '.c.template'),
+ '@INPUT@'],
+ capture: true,
+ )
+
+ sources += custom_target(
+ enums_types + '.h',
+ input: headers,
+ output: enums_types + '.h',
+ command: [
+ python,
+ mm_mkenums,
+ '--fhead', '#include "mm-port-serial-xmmrpc-xmm7360.h"\n#ifndef __MM_XMM7360_ENUMS_TYPES_H__\n#define __MM_XMM7360_ENUMS_TYPES_H__\n',
+ '--template', files(templates_dir / enums_types + '.h.template'),
+ '--ftail', '#endif /* __MM_XMM7360_ENUMS_TYPES_H__ */\n',
+ '@INPUT@'],
+ capture: true,
+ )
+
plugins += {'plugin-intel': {
'plugin': true,
- 'module': {'sources': sources, 'include_directories': plugins_incs + [xmm_inc], 'c_args': common_c_args},
+ 'module': {'sources': sources, 'include_directories': plugins_incs + [xmm_inc, intel_inc], 'c_args': common_c_args},
}}
endif