diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2013-11-20 00:02:13 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2014-06-23 18:12:27 +0200 |
commit | 75a5c48345351585ad176b1a56c76309720248e2 (patch) | |
tree | 3e52fbf4ae2bc9e017d0f49b8feab9ca24cc68ae /plugins | |
parent | 293b032149d387109eab2164da6a7139c068c9bb (diff) |
huawei: use the cdc-wdm port dialing if available
With the new 'huawei-cdc-ncm' driver in the kernel, we now may get a
/dev/cdc-wdm AT-capable port exposed by the Huawei device. If so, we must use
this port for NDISDUP dialling in order to get the network interface connected.
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/huawei/mm-broadband-bearer-huawei.c | 34 | ||||
-rw-r--r-- | plugins/huawei/mm-broadband-modem-huawei.c | 167 | ||||
-rw-r--r-- | plugins/huawei/mm-broadband-modem-huawei.h | 3 |
3 files changed, 177 insertions, 27 deletions
diff --git a/plugins/huawei/mm-broadband-bearer-huawei.c b/plugins/huawei/mm-broadband-bearer-huawei.c index adc62fc4..877916ab 100644 --- a/plugins/huawei/mm-broadband-bearer-huawei.c +++ b/plugins/huawei/mm-broadband-bearer-huawei.c @@ -42,6 +42,25 @@ struct _MMBroadbandBearerHuaweiPrivate { }; /*****************************************************************************/ + +static MMPortSerialAt * +get_dial_port (MMBroadbandModemHuawei *modem, + MMPort *data, + MMPortSerialAt *primary) +{ + MMPortSerialAt *dial_port; + + /* See if we have a cdc-wdm AT port for the interface */ + dial_port = (mm_broadband_modem_huawei_peek_port_at_for_data ( + MM_BROADBAND_MODEM_HUAWEI (modem), data)); + if (dial_port) + return g_object_ref (dial_port); + + /* Otherwise, fallback to using the primary port for dialing */ + return g_object_ref (primary); +} + +/*****************************************************************************/ /* Connect 3GPP */ typedef enum { @@ -67,12 +86,15 @@ static void connect_3gpp_context_complete_and_free (Connect3gppContext *ctx) { g_simple_async_result_complete_in_idle (ctx->result); + g_object_unref (ctx->cancellable); g_object_unref (ctx->result); - g_object_unref (ctx->data); - g_object_unref (ctx->primary); g_object_unref (ctx->modem); g_object_unref (ctx->self); + + g_clear_object (&ctx->data); + g_clear_object (&ctx->primary); + g_slice_free (Connect3gppContext, ctx); } @@ -410,7 +432,6 @@ connect_3gpp (MMBroadbandBearer *self, ctx = g_slice_new0 (Connect3gppContext); ctx->self = g_object_ref (self); ctx->modem = g_object_ref (modem); - ctx->primary = g_object_ref (primary); ctx->data = g_object_ref (data); ctx->result = g_simple_async_result_new (G_OBJECT (self), callback, @@ -422,6 +443,9 @@ connect_3gpp (MMBroadbandBearer *self, g_assert (ctx->self->priv->connect_pending == NULL); g_assert (ctx->self->priv->disconnect_pending == NULL); + /* Get correct dial port to use */ + ctx->primary = get_dial_port (MM_BROADBAND_MODEM_HUAWEI (ctx->modem), ctx->data, primary); + /* Run! */ connect_3gpp_context_step (ctx); } @@ -654,7 +678,6 @@ disconnect_3gpp (MMBroadbandBearer *self, ctx = g_slice_new0 (Disconnect3gppContext); ctx->self = g_object_ref (self); ctx->modem = MM_BASE_MODEM (g_object_ref (modem)); - ctx->primary = g_object_ref (primary); ctx->result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, @@ -664,6 +687,9 @@ disconnect_3gpp (MMBroadbandBearer *self, g_assert (ctx->self->priv->connect_pending == NULL); g_assert (ctx->self->priv->disconnect_pending == NULL); + /* Get correct dial port to use */ + ctx->primary = get_dial_port (MM_BROADBAND_MODEM_HUAWEI (ctx->modem), data, primary); + /* Start! */ disconnect_3gpp_context_step (ctx); } diff --git a/plugins/huawei/mm-broadband-modem-huawei.c b/plugins/huawei/mm-broadband-modem-huawei.c index 1d63ca0e..3dcebe29 100644 --- a/plugins/huawei/mm-broadband-modem-huawei.c +++ b/plugins/huawei/mm-broadband-modem-huawei.c @@ -2098,6 +2098,149 @@ create_bearer_for_net_port (CreateBearerContext *ctx) } } +static MMPortSerialAt * +peek_port_at_for_data (MMBroadbandModemHuawei *self, + MMPort *port) +{ + GUdevClient *client; + GUdevDevice *data_device; + GUdevDevice *data_device_parent = NULL; + GList *cdc_wdm_at_ports = NULL; + GList *l; + MMPortSerialAt *found = NULL; + + client = g_udev_client_new (NULL); + data_device = (g_udev_client_query_by_subsystem_and_name ( + client, + "net", + mm_port_get_device (port))); + + cdc_wdm_at_ports = mm_base_modem_find_ports (MM_BASE_MODEM (self), + MM_PORT_SUBSYS_USB, + MM_PORT_TYPE_AT, + NULL); + + /* Get parent of the data device */ + data_device_parent = g_udev_device_get_parent (data_device); + if (!data_device_parent) { + mm_dbg ("Cannot get parent device (%s)", mm_port_get_device (port)); + goto out; + } + + /* Now walk the list of cdc-wdm AT ports looking for a match */ + for (l = cdc_wdm_at_ports; l && !found; l = g_list_next (l)) { + GUdevDevice *cdc_wdm_device; + GUdevDevice *cdc_wdm_device_parent; + + g_assert (MM_IS_PORT_SERIAL_AT (l->data)); + + /* Get udev device for the cdc-wdm port */ + cdc_wdm_device = (g_udev_client_query_by_subsystem_and_name ( + client, + "usb", + mm_port_get_device (MM_PORT (l->data)))); + if (!cdc_wdm_device) { + cdc_wdm_device = (g_udev_client_query_by_subsystem_and_name ( + client, + "usbmisc", + mm_port_get_device (MM_PORT (l->data)))); + if (!cdc_wdm_device) { + mm_warn ("Couldn't get udev device for cdc-wdm port '%s'", + mm_port_get_device (MM_PORT (l->data))); + continue; + } + } + + /* Get parent of the cdc-wdm device */ + cdc_wdm_device_parent = g_udev_device_get_parent (cdc_wdm_device); + g_object_unref (cdc_wdm_device); + + if (!cdc_wdm_device_parent) { + mm_warn ("Couldn't get udev device parent for cdc-wdm port '%s'", + mm_port_get_device (MM_PORT (l->data))); + continue; + } + + if (g_str_equal (g_udev_device_get_sysfs_path (data_device_parent), + g_udev_device_get_sysfs_path (cdc_wdm_device_parent))) + found = MM_PORT_SERIAL_AT (l->data); + + g_object_unref (cdc_wdm_device_parent); + } + +out: + + if (data_device_parent) + g_object_unref (data_device_parent); + if (data_device) + g_object_unref (data_device); + if (client) + g_object_unref (client); + if (cdc_wdm_at_ports) + g_list_free_full (cdc_wdm_at_ports, (GDestroyNotify)g_object_unref); + + return found; +} + + +MMPortSerialAt * +mm_broadband_modem_huawei_peek_port_at_for_data (MMBroadbandModemHuawei *self, + MMPort *port) +{ + MMPortSerialAt *found; + + g_assert (self->priv->ndisdup_support == FEATURE_SUPPORTED); + + found = peek_port_at_for_data (self, port); + if (!found) + mm_warn ("Couldn't find associated cdc-wdm port for 'net/%s'", + mm_port_get_device (port)); + return found; +} + +static void +ensure_ndisdup_support_checked (MMBroadbandModemHuawei *self, + MMPort *port) +{ + GUdevClient *client; + GUdevDevice *data_device; + + /* Check NDISDUP support the first time we need it */ + if (self->priv->ndisdup_support != FEATURE_SUPPORT_UNKNOWN) + return; + + /* First, check for devices which support NDISDUP on any AT port. These + * devices are tagged by udev */ + client = g_udev_client_new (NULL); + data_device = (g_udev_client_query_by_subsystem_and_name ( + client, + "net", + mm_port_get_device (port))); + if (data_device && g_udev_device_get_property_as_boolean (data_device, "ID_MM_HUAWEI_NDISDUP_SUPPORTED")) { + mm_dbg ("This device (%s) can support ndisdup feature", mm_port_get_device (port)); + self->priv->ndisdup_support = FEATURE_SUPPORTED; + goto out; + } + + /* Then, look for devices which have both a net port and a cdc-wdm + * AT-capable port. We assume that these devices allow NDISDUP only + * when issued in the cdc-wdm port. */ + if (peek_port_at_for_data (self, port)) { + mm_dbg ("This device (%s) can support ndisdup feature on non-serial AT port", + mm_port_get_device (port)); + self->priv->ndisdup_support = FEATURE_SUPPORTED; + goto out; + } + + mm_dbg ("This device (%s) can not support ndisdup feature", mm_port_get_device (port)); + self->priv->ndisdup_support = FEATURE_NOT_SUPPORTED; + +out: + if (data_device) + g_object_unref (data_device); + if (client) + g_object_unref (client); +} static void huawei_modem_create_bearer (MMIfaceModem *self, @@ -2118,28 +2261,7 @@ huawei_modem_create_bearer (MMIfaceModem *self, port = mm_base_modem_peek_best_data_port (MM_BASE_MODEM (self), MM_PORT_TYPE_NET); if (port) { - /* Check NDISDUP support the first time we need it */ - if (ctx->self->priv->ndisdup_support == FEATURE_SUPPORT_UNKNOWN) { - GUdevDevice *net_port; - GUdevClient *client; - - client = g_udev_client_new (NULL); - net_port = (g_udev_client_query_by_subsystem_and_name ( - client, - "net", - mm_port_get_device (port))); - if (net_port && g_udev_device_get_property_as_boolean (net_port, "ID_MM_HUAWEI_NDISDUP_SUPPORTED")) { - mm_dbg ("This device (%s) can support ndisdup feature", mm_port_get_device (port)); - ctx->self->priv->ndisdup_support = FEATURE_SUPPORTED; - } else { - mm_dbg ("This device (%s) can not support ndisdup feature", mm_port_get_device (port)); - ctx->self->priv->ndisdup_support = FEATURE_NOT_SUPPORTED; - } - if (net_port) - g_object_unref (net_port); - g_object_unref (client); - } - + ensure_ndisdup_support_checked (ctx->self, port); create_bearer_for_net_port (ctx); return; } @@ -2152,7 +2274,6 @@ huawei_modem_create_bearer (MMIfaceModem *self, ctx); } - /*****************************************************************************/ /* USSD encode/decode (3GPP-USSD interface) */ diff --git a/plugins/huawei/mm-broadband-modem-huawei.h b/plugins/huawei/mm-broadband-modem-huawei.h index 06874bcf..85bfcdf2 100644 --- a/plugins/huawei/mm-broadband-modem-huawei.h +++ b/plugins/huawei/mm-broadband-modem-huawei.h @@ -48,4 +48,7 @@ MMBroadbandModemHuawei *mm_broadband_modem_huawei_new (const gchar *device, guint16 vendor_id, guint16 product_id); +MMPortSerialAt *mm_broadband_modem_huawei_peek_port_at_for_data (MMBroadbandModemHuawei *self, + MMPort *port); + #endif /* MM_BROADBAND_MODEM_HUAWEI_H */ |