aboutsummaryrefslogtreecommitdiff
path: root/plugins/foxconn
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2019-11-12 10:55:06 +0100
committerAleksander Morgado <aleksander@aleksander.es>2019-11-13 12:31:58 +0100
commitd7d2b9108e12f86f50f82f124066fab46792bd44 (patch)
treee5a599f1155f2e5ec14e2374c608d47601c69ea9 /plugins/foxconn
parent5ab5593edbf86a268f9b6d196f30e303c1e1b879 (diff)
foxconn: new plugin to support the T77W968
The Dell DW5821e is really a re-branded Foxconn T77W968.
Diffstat (limited to 'plugins/foxconn')
-rw-r--r--plugins/foxconn/77-mm-foxconn-port-types.rules26
-rw-r--r--plugins/foxconn/mm-broadband-modem-foxconn-t77w968.c437
-rw-r--r--plugins/foxconn/mm-broadband-modem-foxconn-t77w968.h49
-rw-r--r--plugins/foxconn/mm-foxconn-t77w968-carrier-mapping.conf281
-rw-r--r--plugins/foxconn/mm-plugin-foxconn.c127
-rw-r--r--plugins/foxconn/mm-plugin-foxconn.h46
6 files changed, 966 insertions, 0 deletions
diff --git a/plugins/foxconn/77-mm-foxconn-port-types.rules b/plugins/foxconn/77-mm-foxconn-port-types.rules
new file mode 100644
index 00000000..6b501ba2
--- /dev/null
+++ b/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", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b4", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b4", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_PORT_TYPE_GPS}="1"
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b4", ENV{.MM_USBIFNUM}=="05", ENV{ID_MM_PORT_TYPE_QCDM}="1"
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b5", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b5", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b5", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_PORT_TYPE_GPS}="1"
+ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b5", ENV{.MM_USBIFNUM}=="05", ENV{ID_MM_PORT_TYPE_QCDM}="1"
+
+GOTO="mm_foxconn_port_types_end"
+LABEL="mm_foxconn_port_types_end"
diff --git a/plugins/foxconn/mm-broadband-modem-foxconn-t77w968.c b/plugins/foxconn/mm-broadband-modem-foxconn-t77w968.c
new file mode 100644
index 00000000..c5940194
--- /dev/null
+++ b/plugins/foxconn/mm-broadband-modem-foxconn-t77w968.c
@@ -0,0 +1,437 @@
+/* -*- 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-log.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-foxconn-t77w968.h"
+
+#if defined WITH_QMI
+# include "mm-iface-modem-firmware.h"
+# include "mm-shared-qmi.h"
+#endif
+
+static void iface_modem_location_init (MMIfaceModemLocation *iface);
+
+#if defined WITH_QMI
+static void iface_modem_firmware_init (MMIfaceModemFirmware *iface);
+#endif
+
+static MMIfaceModemLocation *iface_modem_location_parent;
+
+G_DEFINE_TYPE_EXTENDED (MMBroadbandModemFoxconnT77w968, mm_broadband_modem_foxconn_t77w968, MM_TYPE_BROADBAND_MODEM_MBIM, 0,
+#if defined WITH_QMI
+ 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 _MMBroadbandModemFoxconnT77w968Private {
+ FeatureSupport unmanaged_gps_support;
+};
+
+/*****************************************************************************/
+/* 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.
+ */
+
+#if defined WITH_QMI
+
+static MMFirmwareUpdateSettings *
+firmware_load_update_settings_finish (MMIfaceModemFirmware *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_pointer (G_TASK (res), error);
+}
+
+static void
+foxconn_get_firmware_version_ready (QmiClientDms *client,
+ GAsyncResult *res,
+ GTask *task)
+{
+ QmiMessageDmsFoxconnGetFirmwareVersionOutput *output;
+ GError *error = NULL;
+ MMFirmwareUpdateSettings *update_settings = 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))
+ goto out;
+
+ /* Create update settings now */
+ update_settings = mm_firmware_update_settings_new (MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT |
+ MM_MODEM_FIRMWARE_UPDATE_METHOD_QMI_PDC);
+ mm_firmware_update_settings_set_fastboot_at (update_settings, "AT^FASTBOOT");
+
+ qmi_message_dms_foxconn_get_firmware_version_output_get_version (output, &str, NULL);
+ mm_firmware_update_settings_set_version (update_settings, str);
+
+ out:
+ if (error)
+ g_task_return_error (task, error);
+ else {
+ g_assert (update_settings);
+ g_task_return_pointer (task, update_settings, g_object_unref);
+ }
+ g_object_unref (task);
+ if (output)
+ qmi_message_dms_foxconn_get_firmware_version_output_unref (output);
+}
+
+static void
+firmware_load_update_settings (MMIfaceModemFirmware *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ QmiMessageDmsFoxconnGetFirmwareVersionInput *input = NULL;
+ QmiClient *client = NULL;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ client = mm_shared_qmi_peek_client (MM_SHARED_QMI (self),
+ QMI_SERVICE_DMS,
+ MM_PORT_QMI_FLAG_DEFAULT,
+ NULL);
+ if (!client) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Unable to load T77w968 version info: no QMI DMS client available");
+ g_object_unref (task);
+ return;
+ }
+
+ input = qmi_message_dms_foxconn_get_firmware_version_input_new ();
+ qmi_message_dms_foxconn_get_firmware_version_input_set_version_type (
+ input,
+ QMI_DMS_FOXCONN_FIRMWARE_VERSION_TYPE_FIRMWARE_MCFG,
+ NULL);
+ qmi_client_dms_foxconn_get_firmware_version (
+ QMI_CLIENT_DMS (client),
+ input,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)foxconn_get_firmware_version_ready,
+ task);
+ qmi_message_dms_foxconn_get_firmware_version_input_unref (input);
+}
+
+#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
+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;
+ }
+
+ /* 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))) {
+ MM_BROADBAND_MODEM_FOXCONN_T77W968 (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
+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 */
+ iface_modem_location_parent->load_capabilities (self,
+ (GAsyncReadyCallback)parent_load_capabilities_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* 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));
+
+ iface_modem_location_parent->disable_location_gathering (self,
+ source,
+ (GAsyncReadyCallback)parent_disable_location_gathering_ready,
+ 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)
+{
+ MMBroadbandModemFoxconnT77w968 *self = MM_BROADBAND_MODEM_FOXCONN_T77W968 (_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
+parent_enable_location_gathering_ready (MMIfaceModemLocation *_self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemFoxconnT77w968 *self = MM_BROADBAND_MODEM_FOXCONN_T77W968 (_self);
+ GError *error = NULL;
+ MMModemLocationSource source;
+
+ if (!iface_modem_location_parent->enable_location_gathering_finish (_self, res, &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ /* We only support Unmanaged GPS at this level */
+ source = GPOINTER_TO_UINT (g_task_get_task_data (task));
+ 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
+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 */
+ iface_modem_location_parent->enable_location_gathering (self,
+ source,
+ (GAsyncReadyCallback)parent_enable_location_gathering_ready,
+ task);
+}
+
+/*****************************************************************************/
+
+MMBroadbandModemFoxconnT77w968 *
+mm_broadband_modem_foxconn_t77w968_new (const gchar *device,
+ const gchar **drivers,
+ const gchar *plugin,
+ guint16 vendor_id,
+ guint16 product_id)
+{
+ return g_object_new (MM_TYPE_BROADBAND_MODEM_FOXCONN_T77W968,
+ 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,
+ MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED, TRUE,
+ MM_IFACE_MODEM_SIM_HOT_SWAP_CONFIGURED, FALSE,
+ MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED, TRUE,
+ MM_IFACE_MODEM_LOCATION_ALLOW_GPS_UNMANAGED_ALWAYS, TRUE,
+ MM_IFACE_MODEM_CARRIER_CONFIG_MAPPING, PKGDATADIR "/mm-foxconn-t77w968-carrier-mapping.conf",
+ NULL);
+}
+
+static void
+mm_broadband_modem_foxconn_t77w968_init (MMBroadbandModemFoxconnT77w968 *self)
+{
+ /* Initialize private data */
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_BROADBAND_MODEM_FOXCONN_T77W968, MMBroadbandModemFoxconnT77w968Private);
+ 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
+
+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_foxconn_t77w968_class_init (MMBroadbandModemFoxconnT77w968Class *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMBroadbandModemFoxconnT77w968Private));
+}
diff --git a/plugins/foxconn/mm-broadband-modem-foxconn-t77w968.h b/plugins/foxconn/mm-broadband-modem-foxconn-t77w968.h
new file mode 100644
index 00000000..9d145033
--- /dev/null
+++ b/plugins/foxconn/mm-broadband-modem-foxconn-t77w968.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_FOXCONN_T77W968_H
+#define MM_BROADBAND_MODEM_FOXCONN_T77W968_H
+
+#include "mm-broadband-modem-mbim.h"
+
+#define MM_TYPE_BROADBAND_MODEM_FOXCONN_T77W968 (mm_broadband_modem_foxconn_t77w968_get_type ())
+#define MM_BROADBAND_MODEM_FOXCONN_T77W968(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_FOXCONN_T77W968, MMBroadbandModemFoxconnT77w968))
+#define MM_BROADBAND_MODEM_FOXCONN_T77W968_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_FOXCONN_T77W968, MMBroadbandModemFoxconnT77w968Class))
+#define MM_IS_BROADBAND_MODEM_FOXCONN_T77W968(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_FOXCONN_T77W968))
+#define MM_IS_BROADBAND_MODEM_FOXCONN_T77W968_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_FOXCONN_T77W968))
+#define MM_BROADBAND_MODEM_FOXCONN_T77W968_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_FOXCONN_T77W968, MMBroadbandModemFoxconnT77w968Class))
+
+typedef struct _MMBroadbandModemFoxconnT77w968 MMBroadbandModemFoxconnT77w968;
+typedef struct _MMBroadbandModemFoxconnT77w968Class MMBroadbandModemFoxconnT77w968Class;
+typedef struct _MMBroadbandModemFoxconnT77w968Private MMBroadbandModemFoxconnT77w968Private;
+
+struct _MMBroadbandModemFoxconnT77w968 {
+ MMBroadbandModemMbim parent;
+ MMBroadbandModemFoxconnT77w968Private *priv;
+};
+
+struct _MMBroadbandModemFoxconnT77w968Class{
+ MMBroadbandModemMbimClass parent;
+};
+
+GType mm_broadband_modem_foxconn_t77w968_get_type (void);
+
+MMBroadbandModemFoxconnT77w968 *mm_broadband_modem_foxconn_t77w968_new (const gchar *device,
+ const gchar **driver,
+ const gchar *plugin,
+ guint16 vendor_id,
+ guint16 product_id);
+
+#endif /* MM_BROADBAND_MODEM_FOXCONN_T77W968_H */
diff --git a/plugins/foxconn/mm-foxconn-t77w968-carrier-mapping.conf b/plugins/foxconn/mm-foxconn-t77w968-carrier-mapping.conf
new file mode 100644
index 00000000..20639f73
--- /dev/null
+++ b/plugins/foxconn/mm-foxconn-t77w968-carrier-mapping.conf
@@ -0,0 +1,281 @@
+
+#
+# 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
+310680=ATT
+311180=ATT
+
+# FirstNet
+312670=A2
+313100=A2
+313110=A2
+313120=A2
+313130=A2
+313140=A2
+
+# Verizon
+310590=Verizon
+310890=Verizon
+311270=Verizon
+311480=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
+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
+22610=Orange
+23101=Orange
+23430=Orange
+23433=Orange
+23434=Orange
+25901=Orange
+26003=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
+
+# Others
+generic=GCF
diff --git a/plugins/foxconn/mm-plugin-foxconn.c b/plugins/foxconn/mm-plugin-foxconn.c
new file mode 100644
index 00000000..5bd2f886
--- /dev/null
+++ b/plugins/foxconn/mm-plugin-foxconn.c
@@ -0,0 +1,127 @@
+/* -*- 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.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-foxconn-t77w968.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,
+ GList *probes,
+ GError **error)
+{
+#if defined WITH_QMI
+ if (mm_port_probe_list_has_qmi_port (probes)) {
+ mm_dbg ("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)) {
+ /* Specific implementation for the T77W968 */
+ if (product == 0xe0b4 || product == 0xe0b5) {
+ mm_dbg ("MBIM-powered T77W968 modem found...");
+ return MM_BASE_MODEM (mm_broadband_modem_foxconn_t77w968_new (uid,
+ drivers,
+ mm_plugin_get_name (self),
+ vendor,
+ product));
+ }
+
+ mm_dbg ("MBIM-powered Foxconn-branded modem found...");
+ return MM_BASE_MODEM (mm_broadband_modem_mbim_new (uid,
+ drivers,
+ mm_plugin_get_name (self),
+ vendor,
+ product));
+ }
+#endif
+
+ mm_dbg ("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", "usb", NULL };
+ static const guint16 vendors[] = { 0x0489, 0 };
+
+ return MM_PLUGIN (
+ g_object_new (MM_TYPE_PLUGIN_FOXCONN,
+ MM_PLUGIN_NAME, "Foxconn",
+ MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
+ MM_PLUGIN_ALLOWED_VENDOR_IDS, vendors,
+ 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/plugins/foxconn/mm-plugin-foxconn.h b/plugins/foxconn/mm-plugin-foxconn.h
new file mode 100644
index 00000000..4a22ceeb
--- /dev/null
+++ b/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 */