aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mm-plugin.c1
-rw-r--r--src/mm-port-probe.c1006
-rw-r--r--src/mm-port-probe.h2
3 files changed, 533 insertions, 476 deletions
diff --git a/src/mm-plugin.c b/src/mm-plugin.c
index ec3f6e33..78b767d8 100644
--- a/src/mm-plugin.c
+++ b/src/mm-plugin.c
@@ -811,6 +811,7 @@ mm_plugin_supports_port (MMPlugin *self,
self->priv->send_lf,
self->priv->custom_at_probe,
self->priv->custom_init,
+ cancellable,
(GAsyncReadyCallback) port_probe_run_ready,
task);
}
diff --git a/src/mm-port-probe.c b/src/mm-port-probe.c
index e58d18b7..e260f346 100644
--- a/src/mm-port-probe.c
+++ b/src/mm-port-probe.c
@@ -71,56 +71,6 @@ enum {
static GParamSpec *properties[PROP_LAST];
-typedef struct {
- /* ---- Generic task context ---- */
-
- GSimpleAsyncResult *result;
- GCancellable *cancellable;
- guint32 flags;
- guint source_id;
-
- /* ---- Serial probing specific context ---- */
-
- guint buffer_full_id;
- MMPortSerial *serial;
-
- /* ---- AT probing specific context ---- */
-
- GCancellable *at_probing_cancellable;
- /* Send delay for AT commands */
- guint64 at_send_delay;
- /* Flag to leave/remove echo in AT responses */
- gboolean at_remove_echo;
- /* Flag to send line-feed at the end of AT commands */
- gboolean at_send_lf;
- /* Number of times we tried to open the AT port */
- guint at_open_tries;
- /* Custom initialization setup */
- gboolean at_custom_init_run;
- MMPortProbeAtCustomInit at_custom_init;
- MMPortProbeAtCustomInitFinish at_custom_init_finish;
- /* Custom commands to look for AT support */
- const MMPortProbeAtCommand *at_custom_probe;
- /* Current group of AT commands to be sent */
- const MMPortProbeAtCommand *at_commands;
- /* Seconds between each AT command sent in the group */
- guint at_commands_wait_secs;
- /* Current AT Result processor */
- void (* at_result_processor) (MMPortProbe *self,
- GVariant *result);
-
-#if defined WITH_QMI
- /* ---- QMI probing specific context ---- */
- MMPortQmi *port_qmi;
-#endif
-
-#if defined WITH_MBIM
- /* ---- MBIM probing specific context ---- */
- MMPortMbim *mbim_port;
-#endif
-
-} PortProbeRunTask;
-
struct _MMPortProbePrivate {
/* Properties */
MMDevice *device;
@@ -141,9 +91,11 @@ struct _MMPortProbePrivate {
gboolean is_ignored;
/* Current probing task. Only one can be available at a time */
- PortProbeRunTask *task;
+ GTask *task;
};
+/*****************************************************************************/
+
void
mm_port_probe_set_result_at (MMPortProbe *self,
gboolean at)
@@ -323,95 +275,195 @@ mm_port_probe_set_result_mbim (MMPortProbe *self,
g_udev_device_get_name (self->priv->port));
}
-static gboolean serial_probe_at (MMPortProbe *self);
-static gboolean serial_probe_qcdm (MMPortProbe *self);
-static void serial_probe_schedule (MMPortProbe *self);
+/*****************************************************************************/
+
+typedef struct {
+ /* ---- Generic task context ---- */
+ guint32 flags;
+ guint source_id;
+ GCancellable *cancellable;
+
+ /* ---- Serial probing specific context ---- */
+
+ guint buffer_full_id;
+ MMPortSerial *serial;
+
+ /* ---- AT probing specific context ---- */
+
+ GCancellable *at_probing_cancellable;
+ gulong at_probing_cancellable_linked;
+ /* Send delay for AT commands */
+ guint64 at_send_delay;
+ /* Flag to leave/remove echo in AT responses */
+ gboolean at_remove_echo;
+ /* Flag to send line-feed at the end of AT commands */
+ gboolean at_send_lf;
+ /* Number of times we tried to open the AT port */
+ guint at_open_tries;
+ /* Custom initialization setup */
+ gboolean at_custom_init_run;
+ MMPortProbeAtCustomInit at_custom_init;
+ MMPortProbeAtCustomInitFinish at_custom_init_finish;
+ /* Custom commands to look for AT support */
+ const MMPortProbeAtCommand *at_custom_probe;
+ /* Current group of AT commands to be sent */
+ const MMPortProbeAtCommand *at_commands;
+ /* Seconds between each AT command sent in the group */
+ guint at_commands_wait_secs;
+ /* Current AT Result processor */
+ void (* at_result_processor) (MMPortProbe *self,
+ GVariant *result);
+
+#if defined WITH_QMI
+ /* ---- QMI probing specific context ---- */
+ MMPortQmi *port_qmi;
+#endif
+
+#if defined WITH_MBIM
+ /* ---- MBIM probing specific context ---- */
+ MMPortMbim *mbim_port;
+#endif
+
+ /* Error reporting during idle completion */
+ GError *possible_error;
+} PortProbeRunContext;
+
+static gboolean serial_probe_at (MMPortProbe *self);
+static gboolean serial_probe_qcdm (MMPortProbe *self);
+static void serial_probe_schedule (MMPortProbe *self);
static void
-port_probe_run_task_free (PortProbeRunTask *task)
+port_probe_run_context_cleanup (PortProbeRunContext *ctx)
{
- if (task->source_id)
- g_source_remove (task->source_id);
+ /* We cleanup signal connections here, to be executed before a task is
+ * completed (and when it's freed) */
- if (task->serial) {
- if (task->buffer_full_id) {
- g_warn_if_fail (MM_IS_PORT_SERIAL_AT (task->serial));
- g_signal_handler_disconnect (task->serial, task->buffer_full_id);
- }
- if (mm_port_serial_is_open (task->serial))
- mm_port_serial_close (task->serial);
- g_object_unref (task->serial);
+ if (ctx->cancellable && ctx->at_probing_cancellable_linked) {
+ g_cancellable_disconnect (ctx->cancellable, ctx->at_probing_cancellable_linked);
+ ctx->at_probing_cancellable_linked = 0;
+ }
+
+ if (ctx->source_id) {
+ g_source_remove (ctx->source_id);
+ ctx->source_id = 0;
+ }
+
+ if (ctx->serial && ctx->buffer_full_id) {
+ g_signal_handler_disconnect (ctx->serial, ctx->buffer_full_id);
+ ctx->buffer_full_id = 0;
+ }
+}
+
+static void
+port_probe_run_context_free (PortProbeRunContext *ctx)
+{
+ /* Cleanup signals */
+ port_probe_run_context_cleanup (ctx);
+
+ if (ctx->serial) {
+ if (mm_port_serial_is_open (ctx->serial))
+ mm_port_serial_close (ctx->serial);
+ g_object_unref (ctx->serial);
}
#if defined WITH_QMI
- if (task->port_qmi) {
- if (mm_port_qmi_is_open (task->port_qmi))
- mm_port_qmi_close (task->port_qmi);
- g_object_unref (task->port_qmi);
+ if (ctx->port_qmi) {
+ if (mm_port_qmi_is_open (ctx->port_qmi))
+ mm_port_qmi_close (ctx->port_qmi);
+ g_object_unref (ctx->port_qmi);
}
#endif
#if defined WITH_MBIM
- if (task->mbim_port) {
+ if (ctx->mbim_port) {
/* We should have closed it cleanly before */
- g_assert (!mm_port_mbim_is_open (task->mbim_port));
- g_object_unref (task->mbim_port);
+ g_assert (!mm_port_mbim_is_open (ctx->mbim_port));
+ g_object_unref (ctx->mbim_port);
}
#endif
- if (task->cancellable)
- g_object_unref (task->cancellable);
- if (task->at_probing_cancellable)
- g_object_unref (task->at_probing_cancellable);
+ if (ctx->at_probing_cancellable)
+ g_object_unref (ctx->at_probing_cancellable);
+ if (ctx->cancellable)
+ g_object_unref (ctx->cancellable);
+
+ /* We may have an error here if the task was completed
+ * with error and was cancelled at the same time */
+ if (ctx->possible_error)
+ g_error_free (ctx->possible_error);
- g_object_unref (task->result);
- g_free (task);
+ g_slice_free (PortProbeRunContext, ctx);
}
-static void
-port_probe_run_task_complete (PortProbeRunTask *task,
- gboolean result,
- GError *error)
-{
- /* As soon as we have the task completed, disable the buffer-full signal
- * handling, so that we do not get unwanted errors reported */
- if (task->serial && task->buffer_full_id) {
- g_signal_handler_disconnect (task->serial, task->buffer_full_id);
- task->buffer_full_id = 0;
+static gboolean
+task_return_in_idle_cb (GTask *task)
+{
+ PortProbeRunContext *ctx;
+
+ ctx = g_task_get_task_data (task);
+
+ if (g_task_return_error_if_cancelled (task))
+ goto out;
+
+ if (ctx->possible_error) {
+ g_task_return_error (task, ctx->possible_error);
+ ctx->possible_error = NULL;
+ goto out;
}
- if (error)
- g_simple_async_result_take_error (task->result, error);
- else
- g_simple_async_result_set_op_res_gboolean (task->result, result);
+ g_task_return_boolean (task, TRUE);
- /* Always complete in idle */
- g_simple_async_result_complete_in_idle (task->result);
+out:
+ g_object_unref (task);
+ return G_SOURCE_REMOVE;
}
-static gboolean
-port_probe_run_is_cancelled (MMPortProbe *self)
+static void
+task_return_in_idle (MMPortProbe *self,
+ GError *error)
{
- PortProbeRunTask *task = self->priv->task;
-
- /* Manually check if cancelled.
- * TODO: Make the serial port response wait cancellable,
- * so that we can connect a callback to the cancellable and forget about
- * manually checking it.
+ PortProbeRunContext *ctx;
+ GTask *task;
+
+ /* Steal task from private info */
+ g_assert (self->priv->task);
+ task = self->priv->task;
+ self->priv->task = NULL;
+
+ /* Early cleanup of signals */
+ ctx = g_task_get_task_data (task);
+ port_probe_run_context_cleanup (ctx);
+
+ /* We will propatate an error if we have one */
+ ctx->possible_error = error;
+
+ /* Schedule idle to complete.
+ *
+ * NOTE!!!!!!!
+ *
+ * Completing not-on-idle is very problematic due to how we process
+ * responses in the serial port: the response returned by the finish()
+ * call is constant, so that completion is always not-on-idle. And if we
+ * mix both tasks completed not-on-idle, we may end up reaching a point
+ * where the serial port is being closed while the serial port response
+ * is still being processed.
+ *
+ * By always completing this task on-idle, we make sure that the serial
+ * port gets closed always once the response processor has been finished.
*/
- if (g_cancellable_is_cancelled (task->cancellable)) {
- port_probe_run_task_complete (
- task,
- FALSE,
- g_error_new (MM_CORE_ERROR,
- MM_CORE_ERROR_CANCELLED,
- "(%s/%s) port probing cancelled",
- g_udev_device_get_subsystem (self->priv->port),
- g_udev_device_get_name (self->priv->port)));
- return TRUE;
- }
+ g_idle_add ((GSourceFunc) task_return_in_idle_cb, task);
+}
- return FALSE;
+static gboolean
+task_return_error_in_idle_if_cancelled (MMPortProbe *self)
+{
+ if (!g_cancellable_is_cancelled (g_task_get_cancellable (self->priv->task)))
+ return FALSE;
+
+ /* We complete without error because the error is set afterwards by
+ * the GTask in g_task_return_error_if_cancelled() */
+ task_return_in_idle (self, NULL);
+ return TRUE;
}
/***************************************************************/
@@ -422,13 +474,16 @@ static gboolean wdm_probe (MMPortProbe *self);
#if defined WITH_QMI
static void
-port_qmi_open_ready (MMPortQmi *port_qmi,
+port_qmi_open_ready (MMPortQmi *port_qmi,
GAsyncResult *res,
- MMPortProbe *self)
+ MMPortProbe *self)
{
- PortProbeRunTask *task = self->priv->task;
- GError *error = NULL;
- gboolean is_qmi;
+ GError *error = NULL;
+ PortProbeRunContext *ctx;
+ gboolean is_qmi;
+
+ g_assert (self->priv->task);
+ ctx = g_task_get_task_data (self->priv->task);
is_qmi = mm_port_qmi_open_finish (port_qmi, res, &error);
if (!is_qmi) {
@@ -441,11 +496,10 @@ port_qmi_open_ready (MMPortQmi *port_qmi,
/* Set probing result */
mm_port_probe_set_result_qmi (self, is_qmi);
-
mm_port_qmi_close (port_qmi);
/* Keep on */
- task->source_id = g_idle_add ((GSourceFunc)wdm_probe, self);
+ ctx->source_id = g_idle_add ((GSourceFunc) wdm_probe, self);
}
#endif /* WITH_QMI */
@@ -453,7 +507,10 @@ port_qmi_open_ready (MMPortQmi *port_qmi,
static void
wdm_probe_qmi (MMPortProbe *self)
{
- PortProbeRunTask *task = self->priv->task;
+ PortProbeRunContext *ctx;
+
+ g_assert (self->priv->task);
+ ctx = g_task_get_task_data (self->priv->task);
#if defined WITH_QMI
mm_dbg ("(%s/%s) probing QMI...",
@@ -461,42 +518,48 @@ wdm_probe_qmi (MMPortProbe *self)
g_udev_device_get_name (self->priv->port));
/* Create a port and try to open it */
- task->port_qmi = mm_port_qmi_new (g_udev_device_get_name (self->priv->port));
- mm_port_qmi_open (task->port_qmi,
+ ctx->port_qmi = mm_port_qmi_new (g_udev_device_get_name (self->priv->port));
+ mm_port_qmi_open (ctx->port_qmi,
FALSE,
NULL,
- (GAsyncReadyCallback)port_qmi_open_ready,
+ (GAsyncReadyCallback) port_qmi_open_ready,
self);
#else
/* If not compiled with QMI support, just assume we won't have any QMI port */
mm_port_probe_set_result_qmi (self, FALSE);
- task->source_id = g_idle_add ((GSourceFunc)wdm_probe, self);
+ ctx->source_id = g_idle_add ((GSourceFunc) wdm_probe, self);
#endif /* WITH_QMI */
}
#if defined WITH_MBIM
static void
-mbim_port_close_ready (MMPortMbim *mbim_port,
+mbim_port_close_ready (MMPortMbim *mbim_port,
GAsyncResult *res,
- MMPortProbe *self)
+ MMPortProbe *self)
{
- PortProbeRunTask *task = self->priv->task;
+ PortProbeRunContext *ctx;
+
+ g_assert (self->priv->task);
+ ctx = g_task_get_task_data (self->priv->task);
mm_port_mbim_close_finish (mbim_port, res, NULL);
/* Keep on */
- task->source_id = g_idle_add ((GSourceFunc)wdm_probe, self);
+ ctx->source_id = g_idle_add ((GSourceFunc) wdm_probe, self);
}
static void
-mbim_port_open_ready (MMPortMbim *mbim_port,
+mbim_port_open_ready (MMPortMbim *mbim_port,
GAsyncResult *res,
- MMPortProbe *self)
+ MMPortProbe *self)
{
- PortProbeRunTask *task = self->priv->task;
- GError *error = NULL;
- gboolean is_mbim;
+ GError *error = NULL;
+ PortProbeRunContext *ctx;
+ gboolean is_mbim;
+
+ g_assert (self->priv->task);
+ ctx = g_task_get_task_data (self->priv->task);
is_mbim = mm_port_mbim_open_finish (mbim_port, res, &error);
if (!is_mbim) {
@@ -510,8 +573,8 @@ mbim_port_open_ready (MMPortMbim *mbim_port,
/* Set probing result */
mm_port_probe_set_result_mbim (self, is_mbim);
- mm_port_mbim_close (task->mbim_port,
- (GAsyncReadyCallback)mbim_port_close_ready,
+ mm_port_mbim_close (ctx->mbim_port,
+ (GAsyncReadyCallback) mbim_port_close_ready,
self);
}
@@ -520,7 +583,10 @@ mbim_port_open_ready (MMPortMbim *mbim_port,
static void
wdm_probe_mbim (MMPortProbe *self)
{
- PortProbeRunTask *task = self->priv->task;
+ PortProbeRunContext *ctx;
+
+ g_assert (self->priv->task);
+ ctx = g_task_get_task_data (self->priv->task);
#if defined WITH_MBIM
mm_dbg ("(%s/%s) probing MBIM...",
@@ -528,41 +594,47 @@ wdm_probe_mbim (MMPortProbe *self)
g_udev_device_get_name (self->priv->port));
/* Create a port and try to open it */
- task->mbim_port = mm_port_mbim_new (g_udev_device_get_name (self->priv->port));
- mm_port_mbim_open (task->mbim_port,
+ ctx->mbim_port = mm_port_mbim_new (g_udev_device_get_name (self->priv->port));
+ mm_port_mbim_open (ctx->mbim_port,
NULL,
- (GAsyncReadyCallback)mbim_port_open_ready,
+ (GAsyncReadyCallback) mbim_port_open_ready,
self);
#else
/* If not compiled with MBIM support, just assume we won't have any MBIM port */
mm_port_probe_set_result_mbim (self, FALSE);
- task->source_id = g_idle_add ((GSourceFunc)wdm_probe, self);
+ ctx->source_id = g_idle_add ((GSourceFunc) wdm_probe, self);
#endif /* WITH_MBIM */
}
static gboolean
wdm_probe (MMPortProbe *self)
{
- PortProbeRunTask *task = self->priv->task;
+ PortProbeRunContext *ctx;
- task->source_id = 0;
+ g_assert (self->priv->task);
+ ctx = g_task_get_task_data (self->priv->task);
+ ctx->source_id = 0;
/* If already cancelled, do nothing else */
- if (port_probe_run_is_cancelled (self))
- return FALSE;
+ if (task_return_error_in_idle_if_cancelled (self))
+ return G_SOURCE_REMOVE;
- if ((task->flags & MM_PORT_PROBE_QMI) &&
- !(self->priv->flags & MM_PORT_PROBE_QMI))
- /* QMI probing needed */
+ /* QMI probing needed? */
+ if ((ctx->flags & MM_PORT_PROBE_QMI) &&
+ !(self->priv->flags & MM_PORT_PROBE_QMI)) {
wdm_probe_qmi (self);
- else if ((task->flags & MM_PORT_PROBE_MBIM) &&
- !(self->priv->flags & MM_PORT_PROBE_MBIM))
- /* MBIM probing needed */
+ return G_SOURCE_REMOVE;
+ }
+
+ /* MBIM probing needed */
+ if ((ctx->flags & MM_PORT_PROBE_MBIM) &&
+ !(self->priv->flags & MM_PORT_PROBE_MBIM)) {
wdm_probe_mbim (self);
- else
- /* All done now */
- port_probe_run_task_complete (task, TRUE, NULL);
+ return G_SOURCE_REMOVE;
+ }
+ /* All done now */
+ task_return_in_idle (self, NULL);
return G_SOURCE_REMOVE;
}
@@ -571,28 +643,27 @@ wdm_probe (MMPortProbe *self)
static void
serial_probe_qcdm_parse_response (MMPortSerialQcdm *port,
- GAsyncResult *res,
- MMPortProbe *self)
+ GAsyncResult *res,
+ MMPortProbe *self)
{
- QcdmResult *result;
- gint err = QCDM_SUCCESS;
- gboolean is_qcdm = FALSE;
- gboolean retry = FALSE;
- PortProbeRunTask *task = self->priv->task;
- GError *error = NULL;
- GByteArray *response;
+ QcdmResult *result;
+ gint err = QCDM_SUCCESS;
+ gboolean is_qcdm = FALSE;
+ gboolean retry = FALSE;
+ GError *error = NULL;
+ GByteArray *response;
+ PortProbeRunContext *ctx;
- response = mm_port_serial_qcdm_command_finish (port, res, &error);
+ ctx = g_task_get_task_data (self->priv->task);
/* If already cancelled, do nothing else */
- if (port_probe_run_is_cancelled (self))
- goto out;
+ if (task_return_error_in_idle_if_cancelled (self))
+ return;
+ response = mm_port_serial_qcdm_command_finish (port, res, &error);
if (!error) {
/* Parse the response */
- result = qcdm_cmd_version_info_result ((const gchar *) response->data,
- response->len,
- &err);
+ result = qcdm_cmd_version_info_result ((const gchar *) response->data, response->len, &err);
if (!result) {
mm_warn ("(%s/%s) failed to parse QCDM version info command result: %d",
g_udev_device_get_subsystem (self->priv->port),
@@ -604,12 +675,15 @@ serial_probe_qcdm_parse_response (MMPortSerialQcdm *port,
is_qcdm = TRUE;
qcdm_result_unref (result);
}
+ g_byte_array_unref (response);
} else if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_PARSE_FAILED)) {
/* Failed to unescape QCDM packet: don't retry */
mm_dbg ("QCDM parsing error: %s", error->message);
+ g_error_free (error);
} else {
if (!g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT))
mm_dbg ("QCDM probe error: (%d) %s", error->code, error->message);
+ g_error_free (error);
retry = TRUE;
}
@@ -619,46 +693,40 @@ serial_probe_qcdm_parse_response (MMPortSerialQcdm *port,
cmd2 = g_object_steal_data (G_OBJECT (self), "cmd2");
if (cmd2) {
/* second try */
- mm_port_serial_qcdm_command (MM_PORT_SERIAL_QCDM (task->serial),
+ mm_port_serial_qcdm_command (MM_PORT_SERIAL_QCDM (ctx->serial),
cmd2,
3,
NULL,
- (GAsyncReadyCallback)serial_probe_qcdm_parse_response,
+ (GAsyncReadyCallback) serial_probe_qcdm_parse_response,
self);
g_byte_array_unref (cmd2);
- goto out;
+ return;
}
-
/* no more retries left */
}
/* Set probing result */
mm_port_probe_set_result_qcdm (self, is_qcdm);
-
/* Reschedule probing */
serial_probe_schedule (self);
-
-out:
- if (response)
- g_byte_array_unref (response);
- if (error)
- g_error_free (error);
}
static gboolean
serial_probe_qcdm (MMPortProbe *self)
{
- PortProbeRunTask *task = self->priv->task;
- GError *error = NULL;
- GByteArray *verinfo = NULL;
- GByteArray *verinfo2;
- gint len;
- guint8 marker = 0x7E;
+ GError *error = NULL;
+ GByteArray *verinfo = NULL;
+ GByteArray *verinfo2;
+ gint len;
+ guint8 marker = 0x7E;
+ PortProbeRunContext *ctx;
- task->source_id = 0;
+ g_assert (self->priv->task);
+ ctx = g_task_get_task_data (self->priv->task);
+ ctx->source_id = 0;
/* If already cancelled, do nothing else */
- if (port_probe_run_is_cancelled (self))
+ if (task_return_error_in_idle_if_cancelled (self))
return G_SOURCE_REMOVE;
mm_dbg ("(%s/%s) probing QCDM...",
@@ -666,41 +734,37 @@ serial_probe_qcdm (MMPortProbe *self)
g_udev_device_get_name (self->priv->port));
/* If open, close the AT port */
- if (task->serial) {
+ if (ctx->serial) {
/* Explicitly clear the buffer full signal handler */
- if (task->buffer_full_id) {
- g_signal_handler_disconnect (task->serial, task->buffer_full_id);
- task->buffer_full_id = 0;
+ if (ctx->buffer_full_id) {
+ g_signal_handler_disconnect (ctx->serial, ctx->buffer_full_id);
+ ctx->buffer_full_id = 0;
}
- mm_port_serial_close (task->serial);
- g_object_unref (task->serial);
+ mm_port_serial_close (ctx->serial);
+ g_object_unref (ctx->serial);
}
/* Open the QCDM port */
- task->serial = MM_PORT_SERIAL (mm_port_serial_qcdm_new (g_udev_device_get_name (self->priv->port)));
- if (!task->serial) {
- port_probe_run_task_complete (
- task,
- FALSE,
- g_error_new (MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "(%s/%s) Couldn't create QCDM port",
- g_udev_device_get_subsystem (self->priv->port),
- g_udev_device_get_name (self->priv->port)));
+ ctx->serial = MM_PORT_SERIAL (mm_port_serial_qcdm_new (g_udev_device_get_name (self->priv->port)));
+ if (!ctx->serial) {
+ task_return_in_idle (self,
+ g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "(%s/%s) Couldn't create QCDM port",
+ g_udev_device_get_subsystem (self->priv->port),
+ g_udev_device_get_name (self->priv->port)));
return G_SOURCE_REMOVE;
}
/* Try to open the port */
- if (!mm_port_serial_open (task->serial, &error)) {
- port_probe_run_task_complete (
- task,
- FALSE,
- g_error_new (MM_SERIAL_ERROR,
- MM_SERIAL_ERROR_OPEN_FAILED,
- "(%s/%s) Failed to open QCDM port: %s",
- g_udev_device_get_subsystem (self->priv->port),
- g_udev_device_get_name (self->priv->port),
- (error ? error->message : "unknown error")));
+ if (!mm_port_serial_open (ctx->serial, &error)) {
+ task_return_in_idle (self,
+ g_error_new (MM_SERIAL_ERROR,
+ MM_SERIAL_ERROR_OPEN_FAILED,
+ "(%s/%s) Failed to open QCDM port: %s",
+ g_udev_device_get_subsystem (self->priv->port),
+ g_udev_device_get_name (self->priv->port),
+ (error ? error->message : "unknown error")));
g_clear_error (&error);
return G_SOURCE_REMOVE;
}
@@ -715,14 +779,12 @@ serial_probe_qcdm (MMPortProbe *self)
len = qcdm_cmd_version_info_new ((char *) (verinfo->data + 1), 9);
if (len <= 0) {
g_byte_array_unref (verinfo);
- port_probe_run_task_complete (
- task,
- FALSE,
- g_error_new (MM_SERIAL_ERROR,
- MM_SERIAL_ERROR_OPEN_FAILED,
- "(%s/%s) Failed to create QCDM versin info command",
- g_udev_device_get_subsystem (self->priv->port),
- g_udev_device_get_name (self->priv->port)));
+ task_return_in_idle (self,
+ g_error_new (MM_SERIAL_ERROR,
+ MM_SERIAL_ERROR_OPEN_FAILED,
+ "(%s/%s) Failed to create QCDM versin info command",
+ g_udev_device_get_subsystem (self->priv->port),
+ g_udev_device_get_name (self->priv->port)));
return G_SOURCE_REMOVE;
}
verinfo->len = len + 1;
@@ -732,11 +794,11 @@ serial_probe_qcdm (MMPortProbe *self)
g_byte_array_append (verinfo2, verinfo->data, verinfo->len);
g_object_set_data_full (G_OBJECT (self), "cmd2", verinfo2, (GDestroyNotify) g_byte_array_unref);
- mm_port_serial_qcdm_command (MM_PORT_SERIAL_QCDM (task->serial),
+ mm_port_serial_qcdm_command (MM_PORT_SERIAL_QCDM (ctx->serial),
verinfo,
3,
NULL,
- (GAsyncReadyCallback)serial_probe_qcdm_parse_response,
+ (GAsyncReadyCallback) serial_probe_qcdm_parse_response,
self);
g_byte_array_unref (verinfo);
@@ -861,119 +923,121 @@ serial_probe_at_result_processor (MMPortProbe *self,
static void
serial_probe_at_parse_response (MMPortSerialAt *port,
- GAsyncResult *res,
- MMPortProbe *self)
+ GAsyncResult *res,
+ MMPortProbe *self)
{
- PortProbeRunTask *task = self->priv->task;
- GVariant *result = NULL;
- GError *result_error = NULL;
- const gchar *response;
- GError *error = NULL;
+ GVariant *result = NULL;
+ GError *result_error = NULL;
+ const gchar *response = NULL;
+ GError *error = NULL;
+ PortProbeRunContext *ctx;
- response = mm_port_serial_at_command_finish (port, res, &error);
+ g_assert (self->priv->task);
+ ctx = g_task_get_task_data (self->priv->task);
/* If already cancelled, do nothing else */
- if (port_probe_run_is_cancelled (self))
- goto out;
+ if (task_return_error_in_idle_if_cancelled (self))
+ return;
/* If AT probing cancelled, end this partial probing */
- if (g_cancellable_is_cancelled (task->at_probing_cancellable)) {
+ if (g_cancellable_is_cancelled (ctx->at_probing_cancellable)) {
mm_dbg ("(%s/%s) no need to keep on probing the port for AT support",
g_udev_device_get_subsystem (self->priv->port),
g_udev_device_get_name (self->priv->port));
- task->at_result_processor (self, NULL);
+ ctx->at_result_processor (self, NULL);
serial_probe_schedule (self);
- goto out;
+ return;
}
- if (!task->at_commands->response_processor (task->at_commands->command,
- response,
- !!task->at_commands[1].command,
- error,
- &result,
- &result_error)) {
+ response = mm_port_serial_at_command_finish (port, res, &error);
+
+ if (!ctx->at_commands->response_processor (ctx->at_commands->command,
+ response,
+ !!ctx->at_commands[1].command,
+ error,
+ &result,
+ &result_error)) {
/* Were we told to abort the whole probing? */
if (result_error) {
- port_probe_run_task_complete (
- task,
- FALSE,
- g_error_new (MM_CORE_ERROR,
- MM_CORE_ERROR_UNSUPPORTED,
- "(%s/%s) error while probing AT features: %s",
- g_udev_device_get_subsystem (self->priv->port),
- g_udev_device_get_name (self->priv->port),
- result_error->message));
+ task_return_in_idle (self,
+ g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_UNSUPPORTED,
+ "(%s/%s) error while probing AT features: %s",
+ g_udev_device_get_subsystem (self->priv->port),
+ g_udev_device_get_name (self->priv->port),
+ result_error->message));
goto out;
}
/* Go on to next command */
- task->at_commands++;
- if (!task->at_commands->command) {
+ ctx->at_commands++;
+ if (!ctx->at_commands->command) {
/* Was it the last command in the group? If so,
* end this partial probing */
- task->at_result_processor (self, NULL);
+ ctx->at_result_processor (self, NULL);
/* Reschedule */
serial_probe_schedule (self);
goto out;
}
/* Schedule the next command in the probing group */
- if (task->at_commands_wait_secs == 0)
- task->source_id = g_idle_add ((GSourceFunc)serial_probe_at, self);
+ if (ctx->at_commands_wait_secs == 0)
+ ctx->source_id = g_idle_add ((GSourceFunc) serial_probe_at, self);
else {
mm_dbg ("(%s/%s) re-scheduling next command in probing group in %u seconds...",
g_udev_device_get_subsystem (self->priv->port),
g_udev_device_get_name (self->priv->port),
- task->at_commands_wait_secs);
- task->source_id = g_timeout_add_seconds (task->at_commands_wait_secs, (GSourceFunc)serial_probe_at, self);
+ ctx->at_commands_wait_secs);
+ ctx->source_id = g_timeout_add_seconds (ctx->at_commands_wait_secs, (GSourceFunc) serial_probe_at, self);
}
goto out;
}
/* Run result processor.
* Note that custom init commands are allowed to not return anything */
- task->at_result_processor (self, result);
+ ctx->at_result_processor (self, result);
/* Reschedule probing */
serial_probe_schedule (self);
out:
- if (result)
- g_variant_unref (result);
- if (error)
- g_error_free (error);
- if (result_error)
- g_error_free (result_error);
+ g_clear_pointer (&result, g_variant_unref);
+ g_clear_error (&error);
+ g_clear_error (&result_error);
}
static gboolean
serial_probe_at (MMPortProbe *self)
{
- PortProbeRunTask *task = self->priv->task;
+ PortProbeRunContext *ctx;
- task->source_id = 0;
+ g_assert (self->priv->task);
+ ctx = g_task_get_task_data (self->priv->task);
+ ctx->source_id = 0;
/* If already cancelled, do nothing else */
- if (port_probe_run_is_cancelled (self))
+ if (task_return_error_in_idle_if_cancelled (self)) {
+ g_clear_object (&self->priv->task);
return G_SOURCE_REMOVE;
+ }
/* If AT probing cancelled, end this partial probing */
- if (g_cancellable_is_cancelled (task->at_probing_cancellable)) {
+ if (g_cancellable_is_cancelled (ctx->at_probing_cancellable)) {
mm_dbg ("(%s/%s) no need to launch probing for AT support",
g_udev_device_get_subsystem (self->priv->port),
g_udev_device_get_name (self->priv->port));
- task->at_result_processor (self, NULL);
+ ctx->at_result_processor (self, NULL);
serial_probe_schedule (self);
return G_SOURCE_REMOVE;
}
mm_port_serial_at_command (
- MM_PORT_SERIAL_AT (task->serial),
- task->at_commands->command,
- task->at_commands->timeout,
+ MM_PORT_SERIAL_AT (ctx->serial),
+ ctx->at_commands->command,
+ ctx->at_commands->timeout,
FALSE,
FALSE,
- task->at_probing_cancellable,
+ ctx->at_probing_cancellable,
(GAsyncReadyCallback)serial_probe_at_parse_response,
self);
return G_SOURCE_REMOVE;
@@ -1011,17 +1075,20 @@ static void
at_custom_init_ready (MMPortProbe *self,
GAsyncResult *res)
{
- PortProbeRunTask *task = self->priv->task;
- GError *error = NULL;
+ GError *error = NULL;
+ PortProbeRunContext *ctx;
+
+ g_assert (self->priv->task);
+ ctx = g_task_get_task_data (self->priv->task);
- if (!task->at_custom_init_finish (self, res, &error)) {
+ if (!ctx->at_custom_init_finish (self, res, &error)) {
/* All errors propagated up end up forcing an UNSUPPORTED result */
- port_probe_run_task_complete (task, FALSE, error);
+ task_return_in_idle (self, error);
return;
}
/* Keep on with remaining probings */
- task->at_custom_init_run = TRUE;
+ ctx->at_custom_init_run = TRUE;
serial_probe_schedule (self);
}
@@ -1030,80 +1097,83 @@ at_custom_init_ready (MMPortProbe *self,
static void
serial_probe_schedule (MMPortProbe *self)
{
- PortProbeRunTask *task = self->priv->task;
+ PortProbeRunContext *ctx;
+
+ g_assert (self->priv->task);
+ ctx = g_task_get_task_data (self->priv->task);
/* If already cancelled, do nothing else */
- if (port_probe_run_is_cancelled (self))
+ if (task_return_error_in_idle_if_cancelled (self))
return;
/* If we got some custom initialization setup requested, go on with it
* first. */
- if (!task->at_custom_init_run &&
- task->at_custom_init &&
- task->at_custom_init_finish) {
- task->at_custom_init (self,
- MM_PORT_SERIAL_AT (task->serial),
- task->at_probing_cancellable,
- (GAsyncReadyCallback)at_custom_init_ready,
- NULL);
+ if (!ctx->at_custom_init_run &&
+ ctx->at_custom_init &&
+ ctx->at_custom_init_finish) {
+ ctx->at_custom_init (self,
+ MM_PORT_SERIAL_AT (ctx->serial),
+ ctx->at_probing_cancellable,
+ (GAsyncReadyCallback) at_custom_init_ready,
+ NULL);
return;
}
/* Cleanup */
- task->at_result_processor = NULL;
- task->at_commands = NULL;
- task->at_commands_wait_secs = 0;
+ ctx->at_result_processor = NULL;
+ ctx->at_commands = NULL;
+ ctx->at_commands_wait_secs = 0;
/* AT check requested and not already probed? */
- if ((task->flags & MM_PORT_PROBE_AT) &&
+ if ((ctx->flags & MM_PORT_PROBE_AT) &&
!(self->priv->flags & MM_PORT_PROBE_AT)) {
/* Prepare AT probing */
- if (task->at_custom_probe)
- task->at_commands = task->at_custom_probe;
+ if (ctx->at_custom_probe)
+ ctx->at_commands = ctx->at_custom_probe;
else
- task->at_commands = at_probing;
- task->at_result_processor = serial_probe_at_result_processor;
+ ctx->at_commands = at_probing;
+ ctx->at_result_processor = serial_probe_at_result_processor;
}
/* Vendor requested and not already probed? */
- else if ((task->flags & MM_PORT_PROBE_AT_VENDOR) &&
+ else if ((ctx->flags & MM_PORT_PROBE_AT_VENDOR) &&
!(self->priv->flags & MM_PORT_PROBE_AT_VENDOR)) {
/* Prepare AT vendor probing */
- task->at_result_processor = serial_probe_at_vendor_result_processor;
- task->at_commands = vendor_probing;
+ ctx->at_result_processor = serial_probe_at_vendor_result_processor;
+ ctx->at_commands = vendor_probing;
}
/* Product requested and not already probed? */
- else if ((task->flags & MM_PORT_PROBE_AT_PRODUCT) &&
+ else if ((ctx->flags & MM_PORT_PROBE_AT_PRODUCT) &&
!(self->priv->flags & MM_PORT_PROBE_AT_PRODUCT)) {
/* Prepare AT product probing */
- task->at_result_processor = serial_probe_at_product_result_processor;
- task->at_commands = product_probing;
+ ctx->at_result_processor = serial_probe_at_product_result_processor;
+ ctx->at_commands = product_probing;
}
/* Icera support check requested and not already done? */
- else if ((task->flags & MM_PORT_PROBE_AT_ICERA) &&
+ else if ((ctx->flags & MM_PORT_PROBE_AT_ICERA) &&
!(self->priv->flags & MM_PORT_PROBE_AT_ICERA)) {
/* Prepare AT product probing */
- task->at_result_processor = serial_probe_at_icera_result_processor;
- task->at_commands = icera_probing;
+ ctx->at_result_processor = serial_probe_at_icera_result_processor;
+ ctx->at_commands = icera_probing;
/* By default, wait 2 seconds between ICERA probing retries */
- task->at_commands_wait_secs = 2;
+ ctx->at_commands_wait_secs = 2;
}
/* If a next AT group detected, go for it */
- if (task->at_result_processor &&
- task->at_commands) {
- task->source_id = g_idle_add ((GSourceFunc)serial_probe_at, self);
+ if (ctx->at_result_processor &&
+ ctx->at_commands) {
+ ctx->source_id = g_idle_add ((GSourceFunc) serial_probe_at, self);
return;
}
/* QCDM requested and not already probed? */
- if ((task->flags & MM_PORT_PROBE_QCDM) &&
+ if ((ctx->flags & MM_PORT_PROBE_QCDM) &&
!(self->priv->flags & MM_PORT_PROBE_QCDM)) {
- task->source_id = g_idle_add ((GSourceFunc)serial_probe_qcdm, self);
+ ctx->source_id = g_idle_add ((GSourceFunc) serial_probe_qcdm, self);
return;
}
/* All done! Finish asynchronously */
- port_probe_run_task_complete (task, TRUE, NULL);
+ task_return_in_idle (self, NULL);
}
static void
@@ -1119,27 +1189,31 @@ serial_flash_ready (MMPortSerial *port,
static void
serial_buffer_full (MMPortSerial *serial,
- GByteArray *buffer,
- MMPortProbe *self)
+ GByteArray *buffer,
+ MMPortProbe *self)
{
- PortProbeRunTask *task = self->priv->task;
+ PortProbeRunContext *ctx;
- if (is_non_at_response (buffer->data, buffer->len)) {
- mm_dbg ("(%s/%s) serial buffer full",
- g_udev_device_get_subsystem (self->priv->port),
- g_udev_device_get_name (self->priv->port));
- /* Don't explicitly close the AT port, just end the AT probing
- * (or custom init probing) */
- mm_port_probe_set_result_at (self, FALSE);
- g_cancellable_cancel (task->at_probing_cancellable);
- }
+ if (!is_non_at_response (buffer->data, buffer->len))
+ return;
+
+ g_assert (self->priv->task);
+ ctx = g_task_get_task_data (self->priv->task);
+
+ mm_dbg ("(%s/%s) serial buffer full",
+ g_udev_device_get_subsystem (self->priv->port),
+ g_udev_device_get_name (self->priv->port));
+ /* Don't explicitly close the AT port, just end the AT probing
+ * (or custom init probing) */
+ mm_port_probe_set_result_at (self, FALSE);
+ g_cancellable_cancel (ctx->at_probing_cancellable);
}
static gboolean
-serial_parser_filter_cb (gpointer filter,
- gpointer user_data,
- GString *response,
- GError **error)
+serial_parser_filter_cb (gpointer filter,
+ gpointer user_data,
+ GString *response,
+ GError **error)
{
if (is_non_at_response ((const guint8 *) response->str, response->len)) {
g_set_error (error,
@@ -1155,174 +1229,152 @@ serial_parser_filter_cb (gpointer filter,
static gboolean
serial_open_at (MMPortProbe *self)
{
- PortProbeRunTask *task = self->priv->task;
- GError *error = NULL;
+ GError *error = NULL;
+ PortProbeRunContext *ctx;
- task->source_id = 0;
+ g_assert (self->priv->task);
+ ctx = g_task_get_task_data (self->priv->task);
+ ctx->source_id = 0;
/* If already cancelled, do nothing else */
- if (port_probe_run_is_cancelled (self))
+ if (task_return_error_in_idle_if_cancelled (self))
return G_SOURCE_REMOVE;
/* Create AT serial port if not done before */
- if (!task->serial) {
+ if (!ctx->serial) {
gpointer parser;
MMPortSubsys subsys = MM_PORT_SUBSYS_TTY;
if (g_str_has_prefix (g_udev_device_get_subsystem (self->priv->port), "usb"))
subsys = MM_PORT_SUBSYS_USB;
- task->serial = MM_PORT_SERIAL (mm_port_serial_at_new (g_udev_device_get_name (self->priv->port),
- subsys));
- if (!task->serial) {
- port_probe_run_task_complete (
- task,
- FALSE,
- g_error_new (MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "(%s/%s) couldn't create AT port",
- g_udev_device_get_subsystem (self->priv->port),
- g_udev_device_get_name (self->priv->port)));
+ ctx->serial = MM_PORT_SERIAL (mm_port_serial_at_new (g_udev_device_get_name (self->priv->port), subsys));
+ if (!ctx->serial) {
+ task_return_in_idle (self,
+ g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "(%s/%s) couldn't create AT port",
+ g_udev_device_get_subsystem (self->priv->port),
+ g_udev_device_get_name (self->priv->port)));
return G_SOURCE_REMOVE;
}
- g_object_set (task->serial,
+ g_object_set (ctx->serial,
MM_PORT_SERIAL_SPEW_CONTROL, TRUE,
- MM_PORT_SERIAL_SEND_DELAY, (subsys == MM_PORT_SUBSYS_TTY ? task->at_send_delay : 0),
- MM_PORT_SERIAL_AT_REMOVE_ECHO, task->at_remove_echo,
- MM_PORT_SERIAL_AT_SEND_LF, task->at_send_lf,
+ MM_PORT_SERIAL_SEND_DELAY, (subsys == MM_PORT_SUBSYS_TTY ? ctx->at_send_delay : 0),
+ MM_PORT_SERIAL_AT_REMOVE_ECHO, ctx->at_remove_echo,
+ MM_PORT_SERIAL_AT_SEND_LF, ctx->at_send_lf,
NULL);
parser = mm_serial_parser_v1_new ();
mm_serial_parser_v1_add_filter (parser,
serial_parser_filter_cb,
NULL);
- mm_port_serial_at_set_response_parser (MM_PORT_SERIAL_AT (task->serial),
+ mm_port_serial_at_set_response_parser (MM_PORT_SERIAL_AT (ctx->serial),
mm_serial_parser_v1_parse,
parser,
mm_serial_parser_v1_destroy);
}
/* Try to open the port */
- if (!mm_port_serial_open (task->serial, &error)) {
+ if (!mm_port_serial_open (ctx->serial, &error)) {
/* Abort if maximum number of open tries reached */
- if (++task->at_open_tries > 4) {
+ if (++ctx->at_open_tries > 4) {
/* took too long to open the port; give up */
- port_probe_run_task_complete (
- task,
- FALSE,
- g_error_new (MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "(%s/%s) failed to open port after 4 tries",
- g_udev_device_get_subsystem (self->priv->port),
- g_udev_device_get_name (self->priv->port)));
- } else if (g_error_matches (error,
- MM_SERIAL_ERROR,
- MM_SERIAL_ERROR_OPEN_FAILED_NO_DEVICE)) {
+ task_return_in_idle (self,
+ g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "(%s/%s) failed to open port after 4 tries",
+ g_udev_device_get_subsystem (self->priv->port),
+ g_udev_device_get_name (self->priv->port)));
+ g_clear_error (&error);
+ return G_SOURCE_REMOVE;
+ }
+
+ if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_OPEN_FAILED_NO_DEVICE)) {
/* this is nozomi being dumb; try again */
- task->source_id = g_timeout_add_seconds (1,
- (GSourceFunc)serial_open_at,
- self);
- } else {
- port_probe_run_task_complete (
- task,
- FALSE,
- g_error_new (MM_SERIAL_ERROR,
- MM_SERIAL_ERROR_OPEN_FAILED,
- "(%s/%s) failed to open port: %s",
- g_udev_device_get_subsystem (self->priv->port),
- g_udev_device_get_name (self->priv->port),
- (error ? error->message : "unknown error")));
+ ctx->source_id = g_timeout_add_seconds (1, (GSourceFunc) serial_open_at, self);
+ g_clear_error (&error);
+ return G_SOURCE_REMOVE;
}
+ port_probe_run_context_cleanup (ctx);
+ task_return_in_idle (self,
+ g_error_new (MM_SERIAL_ERROR,
+ MM_SERIAL_ERROR_OPEN_FAILED,
+ "(%s/%s) failed to open port: %s",
+ g_udev_device_get_subsystem (self->priv->port),
+ g_udev_device_get_name (self->priv->port),
+ (error ? error->message : "unknown error")));
g_clear_error (&error);
return G_SOURCE_REMOVE;
}
/* success, start probing */
- task->buffer_full_id = g_signal_connect (task->serial,
- "buffer-full",
- G_CALLBACK (serial_buffer_full),
- self);
-
- mm_port_serial_flash (MM_PORT_SERIAL (task->serial),
+ ctx->buffer_full_id = g_signal_connect (ctx->serial, "buffer-full",
+ G_CALLBACK (serial_buffer_full), self);
+ mm_port_serial_flash (MM_PORT_SERIAL (ctx->serial),
100,
TRUE,
- (GAsyncReadyCallback)serial_flash_ready,
+ (GAsyncReadyCallback) serial_flash_ready,
self);
return G_SOURCE_REMOVE;
}
-gboolean
-mm_port_probe_run_cancel_at_probing (MMPortProbe *self)
+static void
+at_cancellable_cancel (GCancellable *main_cancellable,
+ GCancellable *at_cancellable)
{
- g_return_val_if_fail (MM_IS_PORT_PROBE (self), FALSE);
-
- if (self->priv->task) {
- mm_dbg ("(%s/%s) requested to cancel all AT probing",
- g_udev_device_get_subsystem (self->priv->port),
- g_udev_device_get_name (self->priv->port));
- g_cancellable_cancel (self->priv->task->at_probing_cancellable);
- return TRUE;
- }
-
- return FALSE;
+ g_cancellable_cancel (at_cancellable);
}
gboolean
-mm_port_probe_run_cancel (MMPortProbe *self)
+mm_port_probe_run_cancel_at_probing (MMPortProbe *self)
{
+ PortProbeRunContext *ctx;
+
g_return_val_if_fail (MM_IS_PORT_PROBE (self), FALSE);
- if (self->priv->task) {
- mm_dbg ("(%s/%s) requested to cancel the probing",
- g_udev_device_get_subsystem (self->priv->port),
- g_udev_device_get_name (self->priv->port));
- g_cancellable_cancel (self->priv->task->cancellable);
- return TRUE;
- }
+ if (!self->priv->task)
+ return FALSE;
- return FALSE;
+ ctx = g_task_get_task_data (self->priv->task);
+ if (g_cancellable_is_cancelled (ctx->at_probing_cancellable))
+ return FALSE;
+
+ mm_dbg ("(%s/%s) requested to cancel all AT probing",
+ g_udev_device_get_subsystem (self->priv->port),
+ g_udev_device_get_name (self->priv->port));
+ g_cancellable_cancel (ctx->at_probing_cancellable);
+ return TRUE;
}
gboolean
-mm_port_probe_run_finish (MMPortProbe *self,
- GAsyncResult *result,
- GError **error)
+mm_port_probe_run_finish (MMPortProbe *self,
+ GAsyncResult *result,
+ GError **error)
{
- gboolean res;
-
g_return_val_if_fail (MM_IS_PORT_PROBE (self), FALSE);
- g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
-
- /* Propagate error, if any */
- if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
- res = FALSE;
- else
- res = g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result));
-
- /* Cleanup probing task */
- if (self->priv->task) {
- port_probe_run_task_free (self->priv->task);
- self->priv->task = NULL;
- }
- return res;
+ g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
}
void
-mm_port_probe_run (MMPortProbe *self,
- MMPortProbeFlag flags,
- guint64 at_send_delay,
- gboolean at_remove_echo,
- gboolean at_send_lf,
+mm_port_probe_run (MMPortProbe *self,
+ MMPortProbeFlag flags,
+ guint64 at_send_delay,
+ gboolean at_remove_echo,
+ gboolean at_send_lf,
const MMPortProbeAtCommand *at_custom_probe,
- const MMAsyncMethod *at_custom_init,
- GAsyncReadyCallback callback,
- gpointer user_data)
+ const MMAsyncMethod *at_custom_init,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- PortProbeRunTask *task;
- guint32 i;
- gchar *probe_list_str;
+ PortProbeRunContext *ctx;
+ gchar *probe_list_str;
+ guint32 i;
g_return_if_fail (MM_IS_PORT_PROBE (self));
g_return_if_fail (flags != MM_PORT_PROBE_NONE);
@@ -1330,44 +1382,42 @@ mm_port_probe_run (MMPortProbe *self,
/* Shouldn't schedule more than one probing at a time */
g_assert (self->priv->task == NULL);
-
- task = g_new0 (PortProbeRunTask, 1);
- task->at_send_delay = at_send_delay;
- task->at_remove_echo = at_remove_echo;
- task->at_send_lf = at_send_lf;
- task->flags = MM_PORT_PROBE_NONE;
- task->at_custom_probe = at_custom_probe;
- task->at_custom_init = at_custom_init ? (MMPortProbeAtCustomInit)at_custom_init->async : NULL;
- task->at_custom_init_finish = at_custom_init ? (MMPortProbeAtCustomInitFinish)at_custom_init->finish : NULL;
-
- task->result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- mm_port_probe_run);
+ self->priv->task = g_task_new (self, cancellable, callback, user_data);
+
+ /* Task context */
+ ctx = g_slice_new0 (PortProbeRunContext);
+ ctx->at_send_delay = at_send_delay;
+ ctx->at_remove_echo = at_remove_echo;
+ ctx->at_send_lf = at_send_lf;
+ ctx->flags = MM_PORT_PROBE_NONE;
+ ctx->at_custom_probe = at_custom_probe;
+ ctx->at_custom_init = at_custom_init ? (MMPortProbeAtCustomInit)at_custom_init->async : NULL;
+ ctx->at_custom_init_finish = at_custom_init ? (MMPortProbeAtCustomInitFinish)at_custom_init->finish : NULL;
+ ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+
+ /* The context will be owned by the task */
+ g_task_set_task_data (self->priv->task, ctx, (GDestroyNotify) port_probe_run_context_free);
/* Check if we already have the requested probing results.
- * We will fix here the 'task->flags' so that we only request probing
+ * We will fix here the 'ctx->flags' so that we only request probing
* for the missing things. */
for (i = MM_PORT_PROBE_AT; i <= MM_PORT_PROBE_MBIM; i = (i << 1)) {
- if ((flags & i) && !(self->priv->flags & i)) {
- task->flags += i;
- }
+ if ((flags & i) && !(self->priv->flags & i))
+ ctx->flags += i;
}
- /* Store as current task. We need to keep it internally, as it will be
- * freed during _finish() when the operation is completed. */
- self->priv->task = task;
-
/* All requested probings already available? If so, we're done */
- if (!task->flags) {
- port_probe_run_task_complete (task, TRUE, NULL);
+ if (!ctx->flags) {
+ mm_dbg ("(%s/%s) port probing finished: no more probings needed",
+ g_udev_device_get_subsystem (self->priv->port),
+ g_udev_device_get_name (self->priv->port));
+ port_probe_run_context_cleanup (ctx);
+ task_return_in_idle (self, NULL);
return;
}
- /* Setup internal cancellable */
- task->cancellable = g_cancellable_new ();
-
- probe_list_str = mm_port_probe_flag_build_string_from_mask (task->flags);
+ /* Log the probes scheduled to be run */
+ probe_list_str = mm_port_probe_flag_build_string_from_mask (ctx->flags);
mm_dbg ("(%s/%s) launching port probing: '%s'",
g_udev_device_get_subsystem (self->priv->port),
g_udev_device_get_name (self->priv->port),
@@ -1375,24 +1425,30 @@ mm_port_probe_run (MMPortProbe *self,
g_free (probe_list_str);
/* If any AT probing is needed, start by opening as AT port */
- if (task->flags & MM_PORT_PROBE_AT ||
- task->flags & MM_PORT_PROBE_AT_VENDOR ||
- task->flags & MM_PORT_PROBE_AT_PRODUCT ||
- task->flags & MM_PORT_PROBE_AT_ICERA) {
- task->at_probing_cancellable = g_cancellable_new ();
- task->source_id = g_idle_add ((GSourceFunc)serial_open_at, self);
+ if (ctx->flags & MM_PORT_PROBE_AT ||
+ ctx->flags & MM_PORT_PROBE_AT_VENDOR ||
+ ctx->flags & MM_PORT_PROBE_AT_PRODUCT ||
+ ctx->flags & MM_PORT_PROBE_AT_ICERA) {
+ ctx->at_probing_cancellable = g_cancellable_new ();
+ /* If the main cancellable is cancelled, so will be the at-probing one */
+ if (cancellable)
+ ctx->at_probing_cancellable_linked = g_cancellable_connect (cancellable,
+ (GCallback) at_cancellable_cancel,
+ g_object_ref (ctx->at_probing_cancellable),
+ (GDestroyNotify) g_object_unref);
+ ctx->source_id = g_idle_add ((GSourceFunc) serial_open_at, self);
return;
}
/* If QCDM probing needed, start by opening as QCDM port */
- if (task->flags & MM_PORT_PROBE_QCDM) {
- task->source_id = g_idle_add ((GSourceFunc)serial_probe_qcdm, self);
+ if (ctx->flags & MM_PORT_PROBE_QCDM) {
+ ctx->source_id = g_idle_add ((GSourceFunc) serial_probe_qcdm, self);
return;
}
/* If QMI/MBIM probing needed, go on */
- if (task->flags & MM_PORT_PROBE_QMI || task->flags & MM_PORT_PROBE_MBIM) {
- task->source_id = g_idle_add ((GSourceFunc)wdm_probe, self);
+ if (ctx->flags & MM_PORT_PROBE_QMI || ctx->flags & MM_PORT_PROBE_MBIM) {
+ ctx->source_id = g_idle_add ((GSourceFunc) wdm_probe, self);
return;
}
diff --git a/src/mm-port-probe.h b/src/mm-port-probe.h
index 0b3226a0..332cb5a8 100644
--- a/src/mm-port-probe.h
+++ b/src/mm-port-probe.h
@@ -113,12 +113,12 @@ void mm_port_probe_run (MMPortProbe *self,
gboolean at_send_lf,
const MMPortProbeAtCommand *at_custom_probe,
const MMAsyncMethod *at_custom_init,
+ GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_port_probe_run_finish (MMPortProbe *self,
GAsyncResult *result,
GError **error);
-gboolean mm_port_probe_run_cancel (MMPortProbe *self);
gboolean mm_port_probe_run_cancel_at_probing (MMPortProbe *self);