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.
This commit is contained in:
committed by
Aleksander Morgado
parent
293b032149
commit
75a5c48345
@@ -41,6 +41,25 @@ struct _MMBroadbandBearerHuaweiPrivate {
|
||||
guint network_disconnect_pending_id;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user