diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2013-05-07 18:49:57 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2013-05-07 18:49:57 +0200 |
commit | d169c99dc960f02233f65b2fcfb702b76814594f (patch) | |
tree | 5ed57c846d3b74be0befc9fd0a7e2e88cbba1d5e | |
parent | 2c83334c259ef2e1a1f61fa9fb8ac42751933923 (diff) | |
download | ModemManager-d169c99dc960f02233f65b2fcfb702b76814594f.tar.gz |
novatel: skip $NWDMAT if the modem has QMI ports
-rw-r--r-- | plugins/novatel/mm-plugin-novatel.c | 142 |
1 files changed, 141 insertions, 1 deletions
diff --git a/plugins/novatel/mm-plugin-novatel.c b/plugins/novatel/mm-plugin-novatel.c index 673ddb405..4d09f2384 100644 --- a/plugins/novatel/mm-plugin-novatel.c +++ b/plugins/novatel/mm-plugin-novatel.c @@ -24,6 +24,9 @@ #include <string.h> #include <gmodule.h> +#define _LIBMM_INSIDE_MM +#include <libmm-glib.h> + #include "mm-plugin-novatel.h" #include "mm-private-boxed-types.h" #include "mm-broadband-modem-novatel.h" @@ -52,6 +55,139 @@ static const MMPortProbeAtCommand custom_at_probe[] = { }; /*****************************************************************************/ +/* Custom init */ + +typedef struct { + MMPortProbe *probe; + MMAtSerialPort *port; + GCancellable *cancellable; + GSimpleAsyncResult *result; + guint nwdmat_retries; + guint wait_time; +} CustomInitContext; + +static void +custom_init_context_complete_and_free (CustomInitContext *ctx) +{ + g_simple_async_result_complete_in_idle (ctx->result); + + if (ctx->cancellable) + g_object_unref (ctx->cancellable); + g_object_unref (ctx->port); + g_object_unref (ctx->probe); + g_object_unref (ctx->result); + g_slice_free (CustomInitContext, ctx); +} + +static gboolean +novatel_custom_init_finish (MMPortProbe *probe, + GAsyncResult *result, + GError **error) +{ + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); +} + +static void custom_init_step (CustomInitContext *ctx); + +static void +nwdmat_ready (MMAtSerialPort *port, + GString *response, + GError *error, + CustomInitContext *ctx) +{ + if (error) { + if (g_error_matches (error, + MM_SERIAL_ERROR, + MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) { + custom_init_step (ctx); + return; + } + + mm_dbg ("(Novatel) Error flipping secondary ports to AT mode: %s", error->message); + } + + /* Finish custom_init */ + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); + custom_init_context_complete_and_free (ctx); +} + +static gboolean +custom_init_wait_cb (CustomInitContext *ctx) +{ + custom_init_step (ctx); + return FALSE; +} + +static void +custom_init_step (CustomInitContext *ctx) +{ + /* If cancelled, end */ + if (g_cancellable_is_cancelled (ctx->cancellable)) { + mm_dbg ("(Novatel) no need to keep on running custom init in (%s)", + mm_port_get_device (MM_PORT (ctx->port))); + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); + custom_init_context_complete_and_free (ctx); + return; + } + + /* If device has a QMI port, don't run $NWDMAT */ + if (mm_port_probe_list_has_qmi_port (mm_device_peek_port_probe_list (mm_port_probe_peek_device (ctx->probe)))) { + mm_dbg ("(Novatel) no need to run custom init in (%s): device has QMI port", + mm_port_get_device (MM_PORT (ctx->port))); + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); + custom_init_context_complete_and_free (ctx); + return; + } + + if (ctx->wait_time > 0) { + ctx->wait_time--; + g_timeout_add_seconds (1, (GSourceFunc)custom_init_wait_cb, ctx); + return; + } + + if (ctx->nwdmat_retries >= 0) { + ctx->nwdmat_retries--; + mm_at_serial_port_queue_command (ctx->port, + "$NWDMAT=1", + 3, + FALSE, /* raw */ + ctx->cancellable, + (MMAtSerialResponseFn)nwdmat_ready, + ctx); + return; + } + + /* Finish custom_init */ + mm_dbg ("(Novatel) couldn't flip secondary port to AT in (%s): all retries consumed", + mm_port_get_device (MM_PORT (ctx->port))); + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); + custom_init_context_complete_and_free (ctx); +} + +static void +novatel_custom_init (MMPortProbe *probe, + MMAtSerialPort *port, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CustomInitContext *ctx; + + ctx = g_slice_new (CustomInitContext); + ctx->result = g_simple_async_result_new (G_OBJECT (probe), + callback, + user_data, + novatel_custom_init); + ctx->probe = g_object_ref (probe); + ctx->port = g_object_ref (port); + ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + ctx->nwdmat_retries = 3; + ctx->wait_time = 2; + + custom_init_step (ctx); +} + +/*****************************************************************************/ static MMBaseModem * create_modem (MMPlugin *self, @@ -91,6 +227,10 @@ mm_plugin_create (void) 0 }; static const mm_uint16_pair forbidden_products[] = { { 0x1410, 0x9010 }, /* Novatel E362 */ { 0, 0 } }; + static const MMAsyncMethod custom_init = { + .async = G_CALLBACK (novatel_custom_init), + .finish = G_CALLBACK (novatel_custom_init_finish), + }; return MM_PLUGIN ( g_object_new (MM_TYPE_PLUGIN_NOVATEL, @@ -99,7 +239,7 @@ mm_plugin_create (void) MM_PLUGIN_ALLOWED_VENDOR_IDS, vendors, MM_PLUGIN_FORBIDDEN_PRODUCT_IDS, forbidden_products, MM_PLUGIN_ALLOWED_AT, TRUE, - MM_PLUGIN_CUSTOM_AT_PROBE, custom_at_probe, + MM_PLUGIN_CUSTOM_INIT, &custom_init, MM_PLUGIN_ALLOWED_QCDM, TRUE, MM_PLUGIN_ALLOWED_QMI, TRUE, NULL)); |