aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/foxconn
diff options
context:
space:
mode:
authorAleksander Morgado <aleksandermj@chromium.org>2022-12-08 13:37:55 +0000
committerAleksander Morgado <aleksander@aleksander.es>2023-01-03 13:56:25 +0000
commite14b904cbd6816cb0227d519d308ae71ddaf6e07 (patch)
tree4997ab68cc606fdf4d72a571e821cec0c8df42ef /src/plugins/foxconn
parent072d7ac9065f444e83b390a1e2af5471ac0d48f6 (diff)
build: move plugins directory to src/plugins
We are going to allow including the plugin sources built within the ModemManager daemon binary; moving the sources within the daemon sources directory makes it easier.
Diffstat (limited to 'src/plugins/foxconn')
-rw-r--r--src/plugins/foxconn/77-mm-foxconn-port-types.rules26
-rw-r--r--src/plugins/foxconn/mm-broadband-modem-mbim-foxconn.c612
-rw-r--r--src/plugins/foxconn/mm-broadband-modem-mbim-foxconn.h49
-rw-r--r--src/plugins/foxconn/mm-foxconn-t77w968-carrier-mapping.conf319
-rw-r--r--src/plugins/foxconn/mm-plugin-foxconn.c121
-rw-r--r--src/plugins/foxconn/mm-plugin-foxconn.h46
-rw-r--r--src/plugins/foxconn/mm-shared.c20
7 files changed, 1193 insertions, 0 deletions
diff --git a/src/plugins/foxconn/77-mm-foxconn-port-types.rules b/src/plugins/foxconn/77-mm-foxconn-port-types.rules
new file mode 100644
index 00000000..344df152
--- /dev/null
+++ b/src/plugins/foxconn/77-mm-foxconn-port-types.rules
@@ -0,0 +1,26 @@
+# do not edit this file, it will be overwritten on update
+
+ACTION!="add|change|move|bind", GOTO="mm_foxconn_port_types_end"
+
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="0489", GOTO="mm_foxconn_vendorcheck"
+GOTO="mm_foxconn_port_types_end"
+
+LABEL="mm_foxconn_vendorcheck"
+SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
+
+# Foxconn T77w968 (default 0xe0b4, with esim support 0xe0b5)
+# if 02: primary port
+# if 03: secondary port
+# if 04: raw NMEA port
+# if 05: diag/qcdm port
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b4", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b4", ENV{.MM_USBIFNUM}=="03", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b4", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b4", ENV{.MM_USBIFNUM}=="05", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1"
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b5", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b5", ENV{.MM_USBIFNUM}=="03", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b5", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b5", ENV{.MM_USBIFNUM}=="05", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1"
+
+GOTO="mm_foxconn_port_types_end"
+LABEL="mm_foxconn_port_types_end"
diff --git a/src/plugins/foxconn/mm-broadband-modem-mbim-foxconn.c b/src/plugins/foxconn/mm-broadband-modem-mbim-foxconn.c
new file mode 100644
index 00000000..cec1c617
--- /dev/null
+++ b/src/plugins/foxconn/mm-broadband-modem-mbim-foxconn.c
@@ -0,0 +1,612 @@
+/* -*- 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) 2018-2019 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+
+#include <ModemManager.h>
+#define _LIBMM_INSIDE_MM
+#include <libmm-glib.h>
+
+#include "mm-errors-types.h"
+#include "mm-modem-helpers.h"
+#include "mm-base-modem-at.h"
+#include "mm-iface-modem.h"
+#include "mm-iface-modem-location.h"
+#include "mm-broadband-modem-mbim-foxconn.h"
+
+#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
+# include "mm-iface-modem-firmware.h"
+# include "mm-shared-qmi.h"
+# include "mm-log.h"
+#endif
+
+static void iface_modem_location_init (MMIfaceModemLocation *iface);
+
+#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
+static void iface_modem_firmware_init (MMIfaceModemFirmware *iface);
+#endif
+
+static MMIfaceModemLocation *iface_modem_location_parent;
+
+G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbimFoxconn, mm_broadband_modem_mbim_foxconn, MM_TYPE_BROADBAND_MODEM_MBIM, 0,
+#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_FIRMWARE, iface_modem_firmware_init)
+#endif
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init))
+
+typedef enum {
+ FEATURE_SUPPORT_UNKNOWN,
+ FEATURE_NOT_SUPPORTED,
+ FEATURE_SUPPORTED
+} FeatureSupport;
+
+struct _MMBroadbandModemMbimFoxconnPrivate {
+ FeatureSupport unmanaged_gps_support;
+};
+
+
+#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
+
+/*****************************************************************************/
+/* Firmware update settings
+ *
+ * We only support reporting firmware update settings when QMI support is built,
+ * because this is the only clean way to get the expected firmware version to
+ * report.
+ */
+
+static MMFirmwareUpdateSettings *
+firmware_load_update_settings_finish (MMIfaceModemFirmware *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_pointer (G_TASK (res), error);
+}
+
+static gboolean
+needs_qdu_and_mcfg_apps_version (MMIfaceModemFirmware *self)
+{
+ guint vendor_id;
+ guint product_id;
+
+ /* 0x105b is the T99W175 module, T99W175 supports QDU and requires MCFG+APPS version.
+ * T99W265(0x0489:0xe0da ; 0x0489:0xe0db): supports QDU and requires MCFG+APPS version.
+ * else support FASTBOOT and QMI PDC, and require only MCFG version.
+ */
+ vendor_id = mm_base_modem_get_vendor_id (MM_BASE_MODEM (self));
+ product_id = mm_base_modem_get_product_id (MM_BASE_MODEM (self));
+ return (vendor_id == 0x105b || (vendor_id == 0x0489 && (product_id == 0xe0da || product_id == 0xe0db)));
+}
+
+/*****************************************************************************/
+/* Need APPS version for the development of different functions when T77W968 support FASTBOOT and QMI PDC.
+ * Such as: T77W968.F1.0.0.5.2.GC.013.037 and T77W968.F1.0.0.5.2.GC.013.049, the MCFG version(T77W968.F1.0.0.5.2.GC.013) is same,
+ * but the APPS version(037 and 049) is different.
+ *
+ * For T77W968.F1.0.0.5.2.GC.013.049, before the change, "fwupdmgr get-devices" can obtain Current version is T77W968.F1.0.0.5.2.GC.013,
+ * it only include the MCFG version.
+ * After add need APPS version, it shows Current version is T77W968.F1.0.0.5.2.GC.013.049, including the MCFG+APPS version.
+ */
+
+static gboolean
+needs_fastboot_and_qmi_pdc_mcfg_apps_version (MMIfaceModemFirmware *self)
+{
+ guint vendor_id;
+ guint product_id;
+
+ /* T77W968(0x413c:0x81d7 ; 0x413c:0x81e0 ; 0x413c:0x81e4 ; 0x413c:0x81e6): supports FASTBOOT and QMI PDC,
+ * and requires MCFG+APPS version.
+ * else support FASTBOOT and QMI PDC, and require only MCFG version.
+ */
+ vendor_id = mm_base_modem_get_vendor_id (MM_BASE_MODEM (self));
+ product_id = mm_base_modem_get_product_id (MM_BASE_MODEM (self));
+ return (vendor_id == 0x413c && (product_id == 0x81d7 || product_id == 0x81e0 || product_id == 0x81e4 || product_id == 0x81e6));
+}
+
+static MMFirmwareUpdateSettings *
+create_update_settings (MMIfaceModemFirmware *self,
+ const gchar *version_str)
+{
+ MMModemFirmwareUpdateMethod methods = MM_MODEM_FIRMWARE_UPDATE_METHOD_NONE;
+ MMFirmwareUpdateSettings *update_settings = NULL;
+
+ if (needs_qdu_and_mcfg_apps_version (self))
+ methods = MM_MODEM_FIRMWARE_UPDATE_METHOD_MBIM_QDU;
+ else
+ methods = MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT | MM_MODEM_FIRMWARE_UPDATE_METHOD_QMI_PDC;
+
+ update_settings = mm_firmware_update_settings_new (methods);
+ if (methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT)
+ mm_firmware_update_settings_set_fastboot_at (update_settings, "AT^FASTBOOT");
+ mm_firmware_update_settings_set_version (update_settings, version_str);
+ return update_settings;
+}
+
+static void
+dms_foxconn_get_firmware_version_ready (QmiClientDms *client,
+ GAsyncResult *res,
+ GTask *task)
+{
+ g_autoptr(QmiMessageDmsFoxconnGetFirmwareVersionOutput) output = NULL;
+ GError *error = NULL;
+ const gchar *str;
+
+ output = qmi_client_dms_foxconn_get_firmware_version_finish (client, res, &error);
+ if (!output || !qmi_message_dms_foxconn_get_firmware_version_output_get_result (output, &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ qmi_message_dms_foxconn_get_firmware_version_output_get_version (output, &str, NULL);
+
+ g_task_return_pointer (task,
+ create_update_settings (g_task_get_source_object (task), str),
+ g_object_unref);
+ g_object_unref (task);
+}
+
+static void
+fox_get_firmware_version_ready (QmiClientFox *client,
+ GAsyncResult *res,
+ GTask *task)
+{
+ g_autoptr(QmiMessageFoxGetFirmwareVersionOutput) output = NULL;
+ GError *error = NULL;
+ const gchar *str;
+
+ output = qmi_client_fox_get_firmware_version_finish (client, res, &error);
+ if (!output || !qmi_message_fox_get_firmware_version_output_get_result (output, &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ qmi_message_fox_get_firmware_version_output_get_version (output, &str, NULL);
+
+ g_task_return_pointer (task,
+ create_update_settings (g_task_get_source_object (task), str),
+ g_object_unref);
+ g_object_unref (task);
+}
+
+static void
+mbim_port_allocate_qmi_client_ready (MMPortMbim *mbim,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMIfaceModemFirmware *self;
+ QmiClient *fox_client = NULL;
+ QmiClient *dms_client = NULL;
+ g_autoptr(GError) error = NULL;
+
+ self = g_task_get_source_object (task);
+
+ if (!mm_port_mbim_allocate_qmi_client_finish (mbim, res, &error))
+ mm_obj_dbg (self, "Allocate FOX client failed: %s", error->message);
+
+ /* Try to get firmware version over fox service, if it failed to peek client, try dms service. */
+ fox_client = mm_shared_qmi_peek_client (MM_SHARED_QMI (self), QMI_SERVICE_FOX, MM_PORT_QMI_FLAG_DEFAULT, NULL);
+ if (!fox_client) {
+ dms_client = mm_shared_qmi_peek_client (MM_SHARED_QMI (self), QMI_SERVICE_DMS, MM_PORT_QMI_FLAG_DEFAULT, NULL);
+ if (!dms_client) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Unable to load version info: no FOX or DMS client available");
+ g_object_unref (task);
+ return;
+ }
+ }
+
+ if (fox_client) {
+ g_autoptr(QmiMessageFoxGetFirmwareVersionInput) input = NULL;
+
+ input = qmi_message_fox_get_firmware_version_input_new ();
+ qmi_message_fox_get_firmware_version_input_set_version_type (input,
+ (needs_qdu_and_mcfg_apps_version (self) ?
+ QMI_FOX_FIRMWARE_VERSION_TYPE_FIRMWARE_MCFG_APPS :
+ QMI_FOX_FIRMWARE_VERSION_TYPE_FIRMWARE_MCFG),
+ NULL);
+ qmi_client_fox_get_firmware_version (QMI_CLIENT_FOX (fox_client),
+ input,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)fox_get_firmware_version_ready,
+ task);
+ return;
+ }
+
+ if (dms_client) {
+ g_autoptr(QmiMessageDmsFoxconnGetFirmwareVersionInput) input = NULL;
+
+ input = qmi_message_dms_foxconn_get_firmware_version_input_new ();
+ qmi_message_dms_foxconn_get_firmware_version_input_set_version_type (input,
+ ((needs_qdu_and_mcfg_apps_version (self) || needs_fastboot_and_qmi_pdc_mcfg_apps_version (self)) ?
+ QMI_DMS_FOXCONN_FIRMWARE_VERSION_TYPE_FIRMWARE_MCFG_APPS:
+ QMI_DMS_FOXCONN_FIRMWARE_VERSION_TYPE_FIRMWARE_MCFG),
+ NULL);
+ qmi_client_dms_foxconn_get_firmware_version (QMI_CLIENT_DMS (dms_client),
+ input,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)dms_foxconn_get_firmware_version_ready,
+ task);
+ return;
+ }
+
+ g_assert_not_reached ();
+}
+
+static void
+firmware_load_update_settings (MMIfaceModemFirmware *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ MMPortMbim *mbim;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ mbim = mm_broadband_modem_mbim_peek_port_mbim (MM_BROADBAND_MODEM_MBIM (self));
+ mm_port_mbim_allocate_qmi_client (mbim,
+ QMI_SERVICE_FOX,
+ NULL,
+ (GAsyncReadyCallback)mbim_port_allocate_qmi_client_ready,
+ task);
+}
+
+#endif
+
+/*****************************************************************************/
+/* Location capabilities loading (Location interface) */
+
+static MMModemLocationSource
+location_load_capabilities_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ gssize value;
+
+ value = g_task_propagate_int (G_TASK (res), &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return MM_MODEM_LOCATION_SOURCE_NONE;
+ }
+ return (MMModemLocationSource)value;
+}
+
+static void
+custom_location_load_capabilities (GTask *task,
+ MMModemLocationSource sources)
+{
+ MMBroadbandModemMbimFoxconn *self;
+
+ self = g_task_get_source_object (task);
+
+ /* If we have a GPS port and an AT port, enable unmanaged GPS support */
+ if (mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)) &&
+ mm_base_modem_peek_port_gps (MM_BASE_MODEM (self))) {
+ self->priv->unmanaged_gps_support = FEATURE_SUPPORTED;
+ sources |= MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED;
+ }
+
+ /* So we're done, complete */
+ g_task_return_int (task, sources);
+ g_object_unref (task);
+}
+
+static void
+parent_load_capabilities_ready (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMModemLocationSource sources;
+ GError *error = NULL;
+
+ sources = iface_modem_location_parent->load_capabilities_finish (self, res, &error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ custom_location_load_capabilities (task, sources);
+}
+
+static void
+location_load_capabilities (MMIfaceModemLocation *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ /* Chain up parent's setup, if any. If MM is built without QMI support,
+ * the MBIM modem won't have any location capabilities. */
+ if (iface_modem_location_parent &&
+ iface_modem_location_parent->load_capabilities &&
+ iface_modem_location_parent->load_capabilities_finish) {
+ iface_modem_location_parent->load_capabilities (self,
+ (GAsyncReadyCallback)parent_load_capabilities_ready,
+ task);
+ return;
+ }
+
+ custom_location_load_capabilities (task, MM_MODEM_LOCATION_SOURCE_NONE);
+}
+
+/*****************************************************************************/
+/* Disable location gathering (Location interface) */
+
+static gboolean
+disable_location_gathering_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+parent_disable_location_gathering_ready (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (!iface_modem_location_parent->disable_location_gathering_finish (self, res, &error))
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+parent_disable_location_gathering (GTask *task)
+{
+ MMIfaceModemLocation *self;
+ MMModemLocationSource source;
+
+ self = MM_IFACE_MODEM_LOCATION (g_task_get_source_object (task));
+ source = GPOINTER_TO_UINT (g_task_get_task_data (task));
+
+ if (iface_modem_location_parent &&
+ iface_modem_location_parent->disable_location_gathering &&
+ iface_modem_location_parent->disable_location_gathering_finish) {
+ iface_modem_location_parent->disable_location_gathering (
+ self,
+ source,
+ (GAsyncReadyCallback)parent_disable_location_gathering_ready,
+ task);
+ return;
+ }
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+unmanaged_gps_disabled_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (!mm_base_modem_at_command_finish (self, res, &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ parent_disable_location_gathering (task);
+}
+
+static void
+disable_location_gathering (MMIfaceModemLocation *_self,
+ MMModemLocationSource source,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMBroadbandModemMbimFoxconn *self = MM_BROADBAND_MODEM_MBIM_FOXCONN (_self);
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+ g_task_set_task_data (task, GUINT_TO_POINTER (source), NULL);
+
+ /* We only support Unmanaged GPS at this level */
+ if ((self->priv->unmanaged_gps_support != FEATURE_SUPPORTED) ||
+ (source != MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)) {
+ parent_disable_location_gathering (task);
+ return;
+ }
+
+ mm_base_modem_at_command (MM_BASE_MODEM (_self),
+ "^NV=30007,01,\"00\"",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback)unmanaged_gps_disabled_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* Enable location gathering (Location interface) */
+
+static gboolean
+enable_location_gathering_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+unmanaged_gps_enabled_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (!mm_base_modem_at_command_finish (self, res, &error))
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+custom_enable_location_gathering (GTask *task)
+{
+ MMBroadbandModemMbimFoxconn *self;
+ MMModemLocationSource source;
+
+ self = g_task_get_source_object (task);
+ source = GPOINTER_TO_UINT (g_task_get_task_data (task));
+
+ /* We only support Unmanaged GPS at this level */
+ if ((self->priv->unmanaged_gps_support != FEATURE_SUPPORTED) ||
+ (source != MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)) {
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "^NV=30007,01,\"01\"",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback)unmanaged_gps_enabled_ready,
+ task);
+}
+
+static void
+parent_enable_location_gathering_ready (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (!iface_modem_location_parent->enable_location_gathering_finish (self, res, &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ custom_enable_location_gathering (task);
+}
+
+static void
+enable_location_gathering (MMIfaceModemLocation *self,
+ MMModemLocationSource source,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+ g_task_set_task_data (task, GUINT_TO_POINTER (source), NULL);
+
+ /* Chain up parent's gathering enable */
+ if (iface_modem_location_parent &&
+ iface_modem_location_parent->enable_location_gathering &&
+ iface_modem_location_parent->enable_location_gathering_finish) {
+ iface_modem_location_parent->enable_location_gathering (
+ self,
+ source,
+ (GAsyncReadyCallback)parent_enable_location_gathering_ready,
+ task);
+ return;
+ }
+
+ custom_enable_location_gathering (task);
+}
+
+/*****************************************************************************/
+
+MMBroadbandModemMbimFoxconn *
+mm_broadband_modem_mbim_foxconn_new (const gchar *device,
+ const gchar **drivers,
+ const gchar *plugin,
+ guint16 vendor_id,
+ guint16 product_id)
+{
+ const gchar *carrier_config_mapping = NULL;
+
+ /* T77W968 (DW5821e/DW5829e is also T77W968) modules use t77w968 carrier mapping table. */
+ if ((vendor_id == 0x0489 && (product_id == 0xe0b4 || product_id == 0xe0b5)) ||
+ (vendor_id == 0x413c && (product_id == 0x81d7 || product_id == 0x81e0 || product_id == 0x81e4 || product_id == 0x81e6)))
+ carrier_config_mapping = PKGDATADIR "/mm-foxconn-t77w968-carrier-mapping.conf";
+
+ return g_object_new (MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN,
+ MM_BASE_MODEM_DEVICE, device,
+ MM_BASE_MODEM_DRIVERS, drivers,
+ MM_BASE_MODEM_PLUGIN, plugin,
+ MM_BASE_MODEM_VENDOR_ID, vendor_id,
+ MM_BASE_MODEM_PRODUCT_ID, product_id,
+ /* MBIM bearer supports NET only */
+ MM_BASE_MODEM_DATA_NET_SUPPORTED, TRUE,
+ MM_BASE_MODEM_DATA_TTY_SUPPORTED, FALSE,
+ MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED, TRUE,
+ MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED, TRUE,
+ MM_IFACE_MODEM_LOCATION_ALLOW_GPS_UNMANAGED_ALWAYS, TRUE,
+ MM_IFACE_MODEM_CARRIER_CONFIG_MAPPING, carrier_config_mapping,
+ NULL);
+}
+
+static void
+mm_broadband_modem_mbim_foxconn_init (MMBroadbandModemMbimFoxconn *self)
+{
+ /* Initialize private data */
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN, MMBroadbandModemMbimFoxconnPrivate);
+ self->priv->unmanaged_gps_support = FEATURE_SUPPORT_UNKNOWN;
+}
+
+static void
+iface_modem_location_init (MMIfaceModemLocation *iface)
+{
+ iface_modem_location_parent = g_type_interface_peek_parent (iface);
+
+ iface->load_capabilities = location_load_capabilities;
+ iface->load_capabilities_finish = location_load_capabilities_finish;
+ iface->enable_location_gathering = enable_location_gathering;
+ iface->enable_location_gathering_finish = enable_location_gathering_finish;
+ iface->disable_location_gathering = disable_location_gathering;
+ iface->disable_location_gathering_finish = disable_location_gathering_finish;
+}
+
+#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
+
+static void
+iface_modem_firmware_init (MMIfaceModemFirmware *iface)
+{
+ iface->load_update_settings = firmware_load_update_settings;
+ iface->load_update_settings_finish = firmware_load_update_settings_finish;
+}
+
+#endif
+
+static void
+mm_broadband_modem_mbim_foxconn_class_init (MMBroadbandModemMbimFoxconnClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMBroadbandModemMbimFoxconnPrivate));
+}
diff --git a/src/plugins/foxconn/mm-broadband-modem-mbim-foxconn.h b/src/plugins/foxconn/mm-broadband-modem-mbim-foxconn.h
new file mode 100644
index 00000000..374599e4
--- /dev/null
+++ b/src/plugins/foxconn/mm-broadband-modem-mbim-foxconn.h
@@ -0,0 +1,49 @@
+/* -*- 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) 2018-2019 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#ifndef MM_BROADBAND_MODEM_MBIM_FOXCONN_H
+#define MM_BROADBAND_MODEM_MBIM_FOXCONN_H
+
+#include "mm-broadband-modem-mbim.h"
+
+#define MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN (mm_broadband_modem_mbim_foxconn_get_type ())
+#define MM_BROADBAND_MODEM_MBIM_FOXCONN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN, MMBroadbandModemMbimFoxconn))
+#define MM_BROADBAND_MODEM_MBIM_FOXCONN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN, MMBroadbandModemMbimFoxconnClass))
+#define MM_IS_BROADBAND_MODEM_MBIM_FOXCONN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN))
+#define MM_IS_BROADBAND_MODEM_MBIM_FOXCONN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN))
+#define MM_BROADBAND_MODEM_MBIM_FOXCONN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN, MMBroadbandModemMbimFoxconnClass))
+
+typedef struct _MMBroadbandModemMbimFoxconn MMBroadbandModemMbimFoxconn;
+typedef struct _MMBroadbandModemMbimFoxconnClass MMBroadbandModemMbimFoxconnClass;
+typedef struct _MMBroadbandModemMbimFoxconnPrivate MMBroadbandModemMbimFoxconnPrivate;
+
+struct _MMBroadbandModemMbimFoxconn {
+ MMBroadbandModemMbim parent;
+ MMBroadbandModemMbimFoxconnPrivate *priv;
+};
+
+struct _MMBroadbandModemMbimFoxconnClass{
+ MMBroadbandModemMbimClass parent;
+};
+
+GType mm_broadband_modem_mbim_foxconn_get_type (void);
+
+MMBroadbandModemMbimFoxconn *mm_broadband_modem_mbim_foxconn_new (const gchar *device,
+ const gchar **driver,
+ const gchar *plugin,
+ guint16 vendor_id,
+ guint16 product_id);
+
+#endif /* MM_BROADBAND_MODEM_MBIM_FOXCONN_H */
diff --git a/src/plugins/foxconn/mm-foxconn-t77w968-carrier-mapping.conf b/src/plugins/foxconn/mm-foxconn-t77w968-carrier-mapping.conf
new file mode 100644
index 00000000..79b12c1e
--- /dev/null
+++ b/src/plugins/foxconn/mm-foxconn-t77w968-carrier-mapping.conf
@@ -0,0 +1,319 @@
+
+#
+# T77W968 carrier mapping table
+#
+# This table maps the MCCMNC of the SIM card with the corresponding
+# configuration description as reported by the QMI PDC service in
+# this module.
+#
+
+[foxconn t77w968]
+
+# AT&T
+302220=ATT
+302221=ATT
+31030=ATT
+31070=ATT
+31090=ATT
+310150=ATT
+310170=ATT
+310280=ATT
+310380=ATT
+310410=ATT
+310560=ATT
+310650=ATT
+310680=ATT
+310980=ATT
+311180=ATT
+90118=ATT
+
+# FirstNet
+312670=A2
+313100=A2
+313110=A2
+313120=A2
+313130=A2
+313140=A2
+
+# Verizon
+310590=Verizon
+310890=Verizon
+311270=Verizon
+311480=Verizon
+312770=Verizon
+
+# Vodafone
+20205=Vodafone
+20404=Vodafone
+20601=Vodafone
+20810=Vodafone
+21401=Vodafone
+21670=Vodafone
+21910=Vodafone
+22005=Vodafone
+22210=Vodafone
+22601=Vodafone
+23003=Vodafone
+23201=Vodafone
+23415=Vodafone
+23801=Vodafone
+24405=Vodafone
+24602=Vodafone
+24705=Vodafone
+24802=Vodafone
+25001=Vodafone
+26202=Vodafone
+26209=Vodafone
+26801=Vodafone
+27077=Vodafone
+27201=Vodafone
+27402=Vodafone
+27602=Vodafone
+27801=Vodafone
+28001=Vodafone
+28401=Vodafone
+28602=Vodafone
+28802=Vodafone
+29340=Vodafone
+29403=Vodafone
+40004=Vodafone
+40401=Vodafone
+40405=Vodafone
+40411=Vodafone
+40413=Vodafone
+40415=Vodafone
+40420=Vodafone
+40427=Vodafone
+40430=Vodafone
+40443=Vodafone
+40446=Vodafone
+40460=Vodafone
+40484=Vodafone
+40486=Vodafone
+40488=Vodafone
+40566=Vodafone
+40567=Vodafone
+405750=Vodafone
+405751=Vodafone
+405752=Vodafone
+405753=Vodafone
+405754=Vodafone
+405755=Vodafone
+405756=Vodafone
+41302=Vodafone
+42403=Vodafone
+42602=Vodafone
+42702=Vodafone
+46601=Vodafone
+46603=Vodafone
+50213=Vodafone
+50219=Vodafone
+50503=Vodafone
+52503=Vodafone
+52505=Vodafone
+53001=Vodafone
+54201=Vodafone
+60202=Vodafone
+62002=Vodafone
+63001=Vodafone
+63902=Vodafone
+64004=Vodafone
+64304=Vodafone
+64710=Vodafone
+65101=Vodafone
+65501=Vodafone
+73001=Vodafone
+90128=Vodafone
+
+# Orange
+20610=Orange
+20801=Orange
+20802=Orange
+21403=Orange
+21409=Orange
+22610=Orange
+23101=Orange
+23105=Orange
+23430=Orange
+23433=Orange
+23434=Orange
+25901=Orange
+26003=Orange
+26005=Orange
+27099=Orange
+28310=Orange
+
+# Telefonica Movistar
+21405=Telefonica
+21407=Telefonica
+
+# Swisscom
+22801=Swisscom
+29501=Swisscom
+
+# Telstra
+50501=Telstra
+50506=Telstra
+50571=Telstra
+50572=Telstra
+
+# Sprint
+310120=Sprint
+
+# Optus
+50202=Optus
+
+# NTT DoCoMo
+44002=Docomo
+44003=Docomo
+44009=Docomo
+44010=Docomo
+44011=Docomo
+44012=Docomo
+44013=Docomo
+44014=Docomo
+44015=Docomo
+44016=Docomo
+44017=Docomo
+44018=Docomo
+44019=Docomo
+44022=Docomo
+44023=Docomo
+44024=Docomo
+44025=Docomo
+44026=Docomo
+44027=Docomo
+44028=Docomo
+44029=Docomo
+44030=Docomo
+44031=Docomo
+44032=Docomo
+44033=Docomo
+44034=Docomo
+44035=Docomo
+44036=Docomo
+44037=Docomo
+44038=Docomo
+44039=Docomo
+44049=Docomo
+44058=Docomo
+44060=Docomo
+44061=Docomo
+44062=Docomo
+44063=Docomo
+44064=Docomo
+44065=Docomo
+44066=Docomo
+44067=Docomo
+44068=Docomo
+44069=Docomo
+44087=Docomo
+44099=Docomo
+44140=Docomo
+44141=Docomo
+44142=Docomo
+44143=Docomo
+44144=Docomo
+44145=Docomo
+44190=Docomo
+44101=Docomo
+44192=Docomo
+44193=Docomo
+44194=Docomo
+44198=Docomo
+44199=Docomo
+
+# KDDI
+44007=KDDI
+44008=KDDI
+44050=KDDI
+44051=KDDI
+44052=KDDI
+44053=KDDI
+44054=KDDI
+44055=KDDI
+44056=KDDI
+44070=KDDI
+44071=KDDI
+44072=KDDI
+44073=KDDI
+44074=KDDI
+44075=KDDI
+44076=KDDI
+44077=KDDI
+44078=KDDI
+44079=KDDI
+44080=KDDI
+44081=KDDI
+44082=KDDI
+44083=KDDI
+44084=KDDI
+44085=KDDI
+44086=KDDI
+44088=KDDI
+44089=KDDI
+44150=KDDI
+44151=KDDI
+44170=KDDI
+
+# SoftBank
+44000=SBM
+44004=SBM
+44006=SBM
+44020=SBM
+44021=SBM
+44040=SBM
+44041=SBM
+44042=SBM
+44043=SBM
+44044=SBM
+44045=SBM
+44046=SBM
+44047=SBM
+44048=SBM
+44090=SBM
+44092=SBM
+44093=SBM
+44094=SBM
+44095=SBM
+44096=SBM
+44097=SBM
+44098=SBM
+44101=SBM
+44161=SBM
+44162=SBM
+44163=SBM
+44164=SBM
+44165=SBM
+
+# EE UK
+23430=EE
+23431=EE
+23432=EE
+23433=EE
+23434=EE
+23476=EE
+23501=EE
+23502=EE
+23577=EE
+
+# Deutsche Telekom
+20201=DT
+20416=DT
+20420=DT
+21630=DT
+21901=DT
+22603=DT
+22606=DT
+23001=DT
+23102=DT
+23203=DT
+23207=DT
+26002=DT
+26201=DT
+27601=DT
+29401=DT
+29702=DT
+
+# Others
+generic=GCF
diff --git a/src/plugins/foxconn/mm-plugin-foxconn.c b/src/plugins/foxconn/mm-plugin-foxconn.c
new file mode 100644
index 00000000..d248fb05
--- /dev/null
+++ b/src/plugins/foxconn/mm-plugin-foxconn.c
@@ -0,0 +1,121 @@
+/* -*- 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.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2019 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#include <string.h>
+#include <gmodule.h>
+
+#define _LIBMM_INSIDE_MM
+#include <libmm-glib.h>
+
+#include "mm-plugin-foxconn.h"
+#include "mm-log-object.h"
+#include "mm-broadband-modem.h"
+
+#if defined WITH_QMI
+#include "mm-broadband-modem-qmi.h"
+#endif
+
+#if defined WITH_MBIM
+#include "mm-broadband-modem-mbim-foxconn.h"
+#endif
+
+G_DEFINE_TYPE (MMPluginFoxconn, mm_plugin_foxconn, MM_TYPE_PLUGIN)
+
+MM_PLUGIN_DEFINE_MAJOR_VERSION
+MM_PLUGIN_DEFINE_MINOR_VERSION
+
+/*****************************************************************************/
+
+static MMBaseModem *
+create_modem (MMPlugin *self,
+ const gchar *uid,
+ const gchar **drivers,
+ guint16 vendor,
+ guint16 product,
+ guint16 subsystem_vendor,
+ GList *probes,
+ GError **error)
+{
+#if defined WITH_QMI
+ if (mm_port_probe_list_has_qmi_port (probes)) {
+ mm_obj_dbg (self, "QMI-powered Foxconn-branded modem found...");
+ return MM_BASE_MODEM (mm_broadband_modem_qmi_new (uid,
+ drivers,
+ mm_plugin_get_name (self),
+ vendor,
+ product));
+ }
+#endif
+
+#if defined WITH_MBIM
+ if (mm_port_probe_list_has_mbim_port (probes)) {
+ mm_obj_dbg (self, "MBIM-powered Foxconn-branded modem found...");
+ return MM_BASE_MODEM (mm_broadband_modem_mbim_foxconn_new (uid,
+ drivers,
+ mm_plugin_get_name (self),
+ vendor,
+ product));
+ }
+#endif
+
+ mm_obj_dbg (self, "Foxconn-branded generic modem found...");
+ return MM_BASE_MODEM (mm_broadband_modem_new (uid,
+ drivers,
+ mm_plugin_get_name (self),
+ vendor,
+ product));
+}
+
+/*****************************************************************************/
+
+G_MODULE_EXPORT MMPlugin *
+mm_plugin_create (void)
+{
+ static const gchar *subsystems[] = { "tty", "net", "usbmisc", "wwan", NULL };
+ static const guint16 vendor_ids[] = {
+ 0x0489, /* usb vid */
+ 0x105b, /* pci vid */
+ 0 };
+
+ return MM_PLUGIN (
+ g_object_new (MM_TYPE_PLUGIN_FOXCONN,
+ MM_PLUGIN_NAME, MM_MODULE_NAME,
+ MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
+ MM_PLUGIN_ALLOWED_VENDOR_IDS, vendor_ids,
+ MM_PLUGIN_ALLOWED_AT, TRUE,
+ MM_PLUGIN_ALLOWED_QCDM, TRUE,
+ MM_PLUGIN_ALLOWED_QMI, TRUE,
+ MM_PLUGIN_ALLOWED_MBIM, TRUE,
+ NULL));
+}
+
+static void
+mm_plugin_foxconn_init (MMPluginFoxconn *self)
+{
+}
+
+static void
+mm_plugin_foxconn_class_init (MMPluginFoxconnClass *klass)
+{
+ MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
+
+ plugin_class->create_modem = create_modem;
+}
diff --git a/src/plugins/foxconn/mm-plugin-foxconn.h b/src/plugins/foxconn/mm-plugin-foxconn.h
new file mode 100644
index 00000000..4a22ceeb
--- /dev/null
+++ b/src/plugins/foxconn/mm-plugin-foxconn.h
@@ -0,0 +1,46 @@
+/* -*- 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.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2019 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#ifndef MM_PLUGIN_FOXCONN_H
+#define MM_PLUGIN_FOXCONN_H
+
+#include "mm-plugin.h"
+
+#define MM_TYPE_PLUGIN_FOXCONN (mm_plugin_foxconn_get_type ())
+#define MM_PLUGIN_FOXCONN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_FOXCONN, MMPluginFoxconn))
+#define MM_PLUGIN_FOXCONN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_FOXCONN, MMPluginFoxconnClass))
+#define MM_IS_PLUGIN_FOXCONN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_FOXCONN))
+#define MM_IS_PLUGIN_FOXCONN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_FOXCONN))
+#define MM_PLUGIN_FOXCONN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_FOXCONN, MMPluginFoxconnClass))
+
+typedef struct {
+ MMPlugin parent;
+} MMPluginFoxconn;
+
+typedef struct {
+ MMPluginClass parent;
+} MMPluginFoxconnClass;
+
+GType mm_plugin_foxconn_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_FOXCONN_H */
diff --git a/src/plugins/foxconn/mm-shared.c b/src/plugins/foxconn/mm-shared.c
new file mode 100644
index 00000000..3b017574
--- /dev/null
+++ b/src/plugins/foxconn/mm-shared.c
@@ -0,0 +1,20 @@
+/* -*- 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 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#include "mm-shared.h"
+
+MM_SHARED_DEFINE_MAJOR_VERSION
+MM_SHARED_DEFINE_MINOR_VERSION
+MM_SHARED_DEFINE_NAME(Foxconn)