aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2020-08-12 13:11:27 +0200
committerAleksander Morgado <aleksander@aleksander.es>2020-11-04 11:15:19 +0000
commit30f0824ea1473f5d63a27fa4c8095a5b2858ee2d (patch)
tree6b808a5140700a4390c0359e48b64e9ad6fe04dd
parent4fdf28bb56ec30c73de35cef270b787afa7ceaa7 (diff)
huawei: apply GETPORTMODE hints to serial ports in order
The numbers associated to each port mode given by the AT^GETPORTMODE response are not USB interface numbers, they are 'port numbers'. Moreover, these numbers may start either at 0 or at 1, depending on the firmware. The only reasonable way to parse this response is to just gather the order of all the port modes reported, and apply the modes to each serial port found in the system in the same order. Fixes https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/239
-rw-r--r--plugins/huawei/mm-plugin-huawei.c139
1 files changed, 63 insertions, 76 deletions
diff --git a/plugins/huawei/mm-plugin-huawei.c b/plugins/huawei/mm-plugin-huawei.c
index eda6bf05..cf1ed6f8 100644
--- a/plugins/huawei/mm-plugin-huawei.c
+++ b/plugins/huawei/mm-plugin-huawei.c
@@ -28,6 +28,8 @@
#include "mm-log.h"
#include "mm-plugin-huawei.h"
#include "mm-broadband-modem-huawei.h"
+#include "mm-modem-helpers-huawei.h"
+#include "mm-huawei-enums-types.h"
#if defined WITH_QMI
#include "mm-broadband-modem-qmi.h"
@@ -68,12 +70,8 @@ first_interface_context_free (FirstInterfaceContext *ctx)
g_slice_free (FirstInterfaceContext, ctx);
}
-#define TAG_HUAWEI_PCUI_PORT "huawei-pcui-port"
-#define TAG_HUAWEI_MODEM_PORT "huawei-modem-port"
-#define TAG_HUAWEI_NDIS_PORT "huawei-ndis-port"
-#define TAG_HUAWEI_DIAG_PORT "huawei-diag-port"
-#define TAG_GETPORTMODE_SUPPORTED "getportmode-supported"
-#define TAG_AT_PORT_FLAGS "at-port-flags"
+#define TAG_GETPORTMODE_RESULT "getportmode-result"
+#define TAG_AT_PORT_FLAGS "at-port-flags"
typedef struct {
MMPortSerialAt *port;
@@ -100,41 +98,21 @@ huawei_custom_init_finish (MMPortProbe *probe,
static void huawei_custom_init_step (GTask *task);
-static gboolean
-cache_port_mode (MMDevice *device,
- const gchar *reply,
- const gchar *type,
- const gchar *tag)
-{
- gchar *p;
- gulong i;
-
- /* Get the USB interface number of the PCUI port */
- p = strstr (reply, type);
- if (p) {
- errno = 0;
- /* shift by 1 so NULL return from g_object_get_data() means no tag */
- i = 1 + strtol (p + strlen (type), NULL, 10);
- if (i > 0 && i < 256 && errno == 0) {
- g_object_set_data (G_OBJECT (device), tag, GINT_TO_POINTER ((gint) i));
- return TRUE;
- }
- }
- return FALSE;
-}
-
static void
getportmode_ready (MMPortSerialAt *port,
GAsyncResult *res,
GTask *task)
{
+ MMDevice *device;
MMPortProbe *probe;
HuaweiCustomInitContext *ctx;
const gchar *response;
- GError *error = NULL;
+ GArray *modes;
+ g_autoptr(GError) error = NULL;
- probe = g_task_get_source_object (task);
- ctx = g_task_get_task_data (task);
+ probe = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+ device = mm_port_probe_peek_device (probe);
response = mm_port_serial_at_command_finish (port, res, &error);
if (error) {
@@ -143,41 +121,23 @@ getportmode_ready (MMPortSerialAt *port,
/* If any error occurred that was not ERROR or COMMAND NOT SUPPORT then
* retry the command.
*/
- if (!g_error_matches (error,
- MM_MOBILE_EQUIPMENT_ERROR,
- MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN))
- goto out;
-
- /* Port mode not supported */
- } else {
- MMDevice *device;
- guint n_cached_port_modes = 0;
-
- mm_obj_dbg (probe, "port mode layout retrieved");
-
- /* Results are cached in the parent device object */
- device = mm_port_probe_peek_device (probe);
- n_cached_port_modes += cache_port_mode (device, response, "PCUI:", TAG_HUAWEI_PCUI_PORT);
- n_cached_port_modes += cache_port_mode (device, response, "MDM:", TAG_HUAWEI_MODEM_PORT);
- n_cached_port_modes += cache_port_mode (device, response, "NDIS:", TAG_HUAWEI_NDIS_PORT);
- n_cached_port_modes += cache_port_mode (device, response, "DIAG:", TAG_HUAWEI_DIAG_PORT);
- /* GETPORTMODE response format in newer devices... (e.g. E3372) */
- n_cached_port_modes += cache_port_mode (device, response, "pcui:", TAG_HUAWEI_PCUI_PORT);
- n_cached_port_modes += cache_port_mode (device, response, "modem:", TAG_HUAWEI_MODEM_PORT);
-
- if (n_cached_port_modes > 0)
- g_object_set_data (G_OBJECT (device), TAG_GETPORTMODE_SUPPORTED, GUINT_TO_POINTER (TRUE));
-
- /* Mark port as being AT already */
- mm_port_probe_set_result_at (probe, TRUE);
+ if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN))
+ ctx->getportmode_done = TRUE;
+ huawei_custom_init_step (task);
+ return;
}
- ctx->getportmode_done = TRUE;
+ /* Mark port as being AT already */
+ mm_port_probe_set_result_at (probe, TRUE);
-out:
- if (error)
- g_error_free (error);
+ /* Flag as GETPORTMODE already done */
+ ctx->getportmode_done = TRUE;
+ modes = mm_huawei_parse_getportmode_response (response, probe, &error);
+ if (!modes)
+ mm_obj_warn (probe, "failed to parse ^GETPORTMODE response: %s", error->message);
+ else
+ g_object_set_data_full (G_OBJECT (device), TAG_GETPORTMODE_RESULT, modes, (GDestroyNotify) g_array_unref);
huawei_custom_init_step (task);
}
@@ -427,50 +387,77 @@ huawei_custom_init (MMPortProbe *probe,
/*****************************************************************************/
+static gint
+probe_cmp_by_usbif (MMPortProbe *a,
+ MMPortProbe *b)
+{
+ return ((gint) mm_kernel_device_get_property_as_int_hex (mm_port_probe_peek_port (a), "ID_USB_INTERFACE_NUM") -
+ (gint) mm_kernel_device_get_property_as_int_hex (mm_port_probe_peek_port (b), "ID_USB_INTERFACE_NUM"));
+}
+
static guint
propagate_getportmode_hints (MMPlugin *self,
GList *probes,
gboolean *primary_flagged)
{
MMDevice *device;
+ GArray *modes;
GList *l;
+ GList *tty_probes = NULL;
guint n_ports_with_hints = 0;
+ guint mode_i = 0;
g_assert (probes != NULL);
device = mm_port_probe_peek_device (MM_PORT_PROBE (probes->data));
+ modes = g_object_get_data (G_OBJECT (device), TAG_GETPORTMODE_RESULT);
/* Nothing to do if GETPORTMODE is flagged as not supported */
- if (!GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (device), TAG_GETPORTMODE_SUPPORTED)))
+ if (!modes)
return 0;
- /* Propagate the getportmode tags to the specific port probes */
+ /* Build a list of TTY port probes (AT and not-AT) sorted by interface number */
for (l = probes; l; l = g_list_next (l)) {
+ MMPortProbe *probe;
+
+ probe = MM_PORT_PROBE (l->data);
+ if (g_str_equal (mm_port_probe_get_port_subsys (probe), "tty"))
+ tty_probes = g_list_insert_sorted (tty_probes, probe, (GCompareFunc) probe_cmp_by_usbif);
+ }
+
+ /* Propagate the getportmode tags to the specific port probes */
+ for (l = tty_probes, mode_i = 0; l; l = g_list_next (l)) {
MMPortProbe *probe;
MMPortSerialAtFlag at_port_flags = MM_PORT_SERIAL_AT_FLAG_NONE;
- guint usbif;
+ MMHuaweiPortMode port_mode;
probe = MM_PORT_PROBE (l->data);
- if (!mm_port_probe_is_at (probe))
+ /* Look for the next serial port mode applicable */
+ while (!MM_HUAWEI_PORT_MODE_IS_SERIAL (g_array_index (modes, MMHuaweiPortMode, mode_i)) && (mode_i < modes->len))
+ mode_i++;
+ if (mode_i == modes->len) {
+ mm_obj_dbg (probe, "missing port mode hint");
continue;
+ }
- usbif = mm_kernel_device_get_property_as_int_hex (mm_port_probe_peek_port (probe), "ID_USB_INTERFACE_NUM");
+ port_mode = g_array_index (modes, MMHuaweiPortMode, mode_i);
+ if (!mm_port_probe_is_at (probe)) {
+ mm_obj_dbg (probe, "port mode hint for non-AT port: %s", mm_huawei_port_mode_get_string (port_mode));
+ mode_i++;
+ continue;
+ }
- if (usbif + 1 == GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (device), TAG_HUAWEI_PCUI_PORT))) {
+ mm_obj_dbg (probe, "port mode hint for AT port: %s", mm_huawei_port_mode_get_string (port_mode));
+ if (port_mode == MM_HUAWEI_PORT_MODE_PCUI)
at_port_flags = MM_PORT_SERIAL_AT_FLAG_PRIMARY;
- *primary_flagged = TRUE;
- } else if (usbif + 1 == GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (device), TAG_HUAWEI_MODEM_PORT))) {
+ else if (port_mode == MM_HUAWEI_PORT_MODE_MODEM)
at_port_flags = MM_PORT_SERIAL_AT_FLAG_PPP;
- } else if (!g_object_get_data (G_OBJECT (device), TAG_HUAWEI_MODEM_PORT) &&
- usbif + 1 == GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (device), TAG_HUAWEI_NDIS_PORT))) {
- /* If NDIS reported only instead of MDM, use it */
- at_port_flags = MM_PORT_SERIAL_AT_FLAG_PPP;
- }
if (at_port_flags != MM_PORT_SERIAL_AT_FLAG_NONE) {
n_ports_with_hints++;
g_object_set_data (G_OBJECT (probe), TAG_AT_PORT_FLAGS, GUINT_TO_POINTER (at_port_flags));
}
+ mode_i++;
}
return n_ports_with_hints;