mbim-port: make port closing async always

Don't just close the port and forget, really wait to get the CLOSE response
before going on.
This commit is contained in:
Aleksander Morgado
2013-04-11 19:21:21 +02:00
parent d1d5616ca5
commit 659d942c33
4 changed files with 119 additions and 56 deletions

View File

@@ -876,9 +876,8 @@ finalize (GObject *object)
mbim = mm_base_modem_peek_port_mbim (MM_BASE_MODEM (self)); mbim = mm_base_modem_peek_port_mbim (MM_BASE_MODEM (self));
/* If we did open the MBIM port during initialization, close it now */ /* If we did open the MBIM port during initialization, close it now */
if (mbim && if (mbim && mm_mbim_port_is_open (mbim)) {
mm_mbim_port_is_open (mbim)) { mm_mbim_port_close (mbim, NULL, NULL);
mm_mbim_port_close (mbim);
} }
G_OBJECT_CLASS (mm_broadband_modem_mbim_parent_class)->finalize (object); G_OBJECT_CLASS (mm_broadband_modem_mbim_parent_class)->finalize (object);

View File

@@ -25,7 +25,7 @@
G_DEFINE_TYPE (MMMbimPort, mm_mbim_port, MM_TYPE_PORT) G_DEFINE_TYPE (MMMbimPort, mm_mbim_port, MM_TYPE_PORT)
struct _MMMbimPortPrivate { struct _MMMbimPortPrivate {
gboolean opening; gboolean in_progress;
MbimDevice *mbim_device; MbimDevice *mbim_device;
}; };
@@ -35,19 +35,39 @@ typedef struct {
MMMbimPort *self; MMMbimPort *self;
GSimpleAsyncResult *result; GSimpleAsyncResult *result;
GCancellable *cancellable; GCancellable *cancellable;
} PortOpenContext; } PortContext;
static void static void
port_open_context_complete_and_free (PortOpenContext *ctx) port_context_complete_and_free (PortContext *ctx)
{ {
g_simple_async_result_complete_in_idle (ctx->result); g_simple_async_result_complete_in_idle (ctx->result);
if (ctx->cancellable) if (ctx->cancellable)
g_object_unref (ctx->cancellable); g_object_unref (ctx->cancellable);
g_object_unref (ctx->result); g_object_unref (ctx->result);
g_object_unref (ctx->self); g_object_unref (ctx->self);
g_slice_free (PortOpenContext, ctx); g_slice_free (PortContext, ctx);
} }
static PortContext *
port_context_new (MMMbimPort *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
PortContext *ctx;
ctx = g_slice_new0 (PortContext);
ctx->self = g_object_ref (self);
ctx->result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
port_context_new);
ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
return ctx;
}
/*****************************************************************************/
gboolean gboolean
mm_mbim_port_open_finish (MMMbimPort *self, mm_mbim_port_open_finish (MMMbimPort *self,
GAsyncResult *res, GAsyncResult *res,
@@ -59,12 +79,12 @@ mm_mbim_port_open_finish (MMMbimPort *self,
static void static void
mbim_device_open_ready (MbimDevice *mbim_device, mbim_device_open_ready (MbimDevice *mbim_device,
GAsyncResult *res, GAsyncResult *res,
PortOpenContext *ctx) PortContext *ctx)
{ {
GError *error = NULL; GError *error = NULL;
/* Reset the opening flag */ /* Reset the progress flag */
ctx->self->priv->opening = FALSE; ctx->self->priv->in_progress = FALSE;
if (!mbim_device_open_finish (mbim_device, res, &error)) { if (!mbim_device_open_finish (mbim_device, res, &error)) {
g_clear_object (&ctx->self->priv->mbim_device); g_clear_object (&ctx->self->priv->mbim_device);
@@ -72,20 +92,20 @@ mbim_device_open_ready (MbimDevice *mbim_device,
} else } else
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
port_open_context_complete_and_free (ctx); port_context_complete_and_free (ctx);
} }
static void static void
mbim_device_new_ready (GObject *unused, mbim_device_new_ready (GObject *unused,
GAsyncResult *res, GAsyncResult *res,
PortOpenContext *ctx) PortContext *ctx)
{ {
GError *error = NULL; GError *error = NULL;
ctx->self->priv->mbim_device = mbim_device_new_finish (res, &error); ctx->self->priv->mbim_device = mbim_device_new_finish (res, &error);
if (!ctx->self->priv->mbim_device) { if (!ctx->self->priv->mbim_device) {
g_simple_async_result_take_error (ctx->result, error); g_simple_async_result_take_error (ctx->result, error);
port_open_context_complete_and_free (ctx); port_context_complete_and_free (ctx);
return; return;
} }
@@ -105,37 +125,31 @@ mm_mbim_port_open (MMMbimPort *self,
{ {
GFile *file; GFile *file;
gchar *fullpath; gchar *fullpath;
PortOpenContext *ctx; PortContext *ctx;
g_return_if_fail (MM_IS_MBIM_PORT (self)); g_return_if_fail (MM_IS_MBIM_PORT (self));
ctx = g_slice_new0 (PortOpenContext); ctx = port_context_new (self, cancellable, callback, user_data);
ctx->self = g_object_ref (self);
ctx->result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
mm_mbim_port_open);
ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
if (self->priv->opening) { if (self->priv->in_progress) {
g_simple_async_result_set_error (ctx->result, g_simple_async_result_set_error (ctx->result,
MM_CORE_ERROR, MM_CORE_ERROR,
MM_CORE_ERROR_IN_PROGRESS, MM_CORE_ERROR_IN_PROGRESS,
"MBIM device already being opened"); "MBIM device open/close operation in progress");
port_open_context_complete_and_free (ctx); port_context_complete_and_free (ctx);
return; return;
} }
if (self->priv->mbim_device) { if (self->priv->mbim_device) {
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
port_open_context_complete_and_free (ctx); port_context_complete_and_free (ctx);
return; return;
} }
fullpath = g_strdup_printf ("/dev/%s", mm_port_get_device (MM_PORT (self))); fullpath = g_strdup_printf ("/dev/%s", mm_port_get_device (MM_PORT (self)));
file = g_file_new_for_path (fullpath); file = g_file_new_for_path (fullpath);
self->priv->opening = TRUE; self->priv->in_progress = TRUE;
mbim_device_new (file, mbim_device_new (file,
ctx->cancellable, ctx->cancellable,
(GAsyncReadyCallback)mbim_device_new_ready, (GAsyncReadyCallback)mbim_device_new_ready,
@@ -145,6 +159,8 @@ mm_mbim_port_open (MMMbimPort *self,
g_object_unref (file); g_object_unref (file);
} }
/*****************************************************************************/
gboolean gboolean
mm_mbim_port_is_open (MMMbimPort *self) mm_mbim_port_is_open (MMMbimPort *self)
{ {
@@ -153,35 +169,66 @@ mm_mbim_port_is_open (MMMbimPort *self)
return !!self->priv->mbim_device; return !!self->priv->mbim_device;
} }
/*****************************************************************************/
gboolean
mm_mbim_port_close_finish (MMMbimPort *self,
GAsyncResult *res,
GError **error)
{
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
}
static void static void
mbim_device_close_ready (MbimDevice *device, mbim_device_close_ready (MbimDevice *device,
GAsyncResult *res) GAsyncResult *res,
PortContext *ctx)
{ {
GError *error = NULL; GError *error = NULL;
if (!mbim_device_close_finish (device, res, &error)) { if (!mbim_device_close_finish (device, res, &error))
mm_warn ("Couldn't properly close MBIM device: %s", g_simple_async_result_take_error (ctx->result, error);
error->message); else
g_error_free (error); g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
}
ctx->self->priv->in_progress = FALSE;
g_clear_object (&ctx->self->priv->mbim_device);
port_context_complete_and_free (ctx);
} }
void void
mm_mbim_port_close (MMMbimPort *self) mm_mbim_port_close (MMMbimPort *self,
GAsyncReadyCallback callback,
gpointer user_data)
{ {
PortContext *ctx;
g_return_if_fail (MM_IS_MBIM_PORT (self)); g_return_if_fail (MM_IS_MBIM_PORT (self));
if (!self->priv->mbim_device) ctx = port_context_new (self, NULL, callback, user_data);
return;
/* Close and release the device. This method is async, if (self->priv->in_progress) {
* but we don't really care about the result. */ g_simple_async_result_set_error (ctx->result,
MM_CORE_ERROR,
MM_CORE_ERROR_IN_PROGRESS,
"MBIM device open/close operation in progress");
port_context_complete_and_free (ctx);
return;
}
if (!self->priv->mbim_device) {
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
port_context_complete_and_free (ctx);
return;
}
self->priv->in_progress = TRUE;
mbim_device_close (self->priv->mbim_device, mbim_device_close (self->priv->mbim_device,
5, 5,
NULL, NULL,
(GAsyncReadyCallback)mbim_device_close_ready, (GAsyncReadyCallback)mbim_device_close_ready,
NULL); ctx);
g_clear_object (&self->priv->mbim_device); g_clear_object (&self->priv->mbim_device);
} }

View File

@@ -48,15 +48,20 @@ GType mm_mbim_port_get_type (void);
MMMbimPort *mm_mbim_port_new (const gchar *name); MMMbimPort *mm_mbim_port_new (const gchar *name);
void mm_mbim_port_open (MMMbimPort *self, void mm_mbim_port_open (MMMbimPort *self,
GCancellable *cancellable, GCancellable *cancellable,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data); gpointer user_data);
gboolean mm_mbim_port_open_finish (MMMbimPort *self, gboolean mm_mbim_port_open_finish (MMMbimPort *self,
GAsyncResult *res, GAsyncResult *res,
GError **error); GError **error);
gboolean mm_mbim_port_is_open (MMMbimPort *self); gboolean mm_mbim_port_is_open (MMMbimPort *self);
void mm_mbim_port_close (MMMbimPort *self); void mm_mbim_port_close (MMMbimPort *self,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_mbim_port_close_finish (MMMbimPort *self,
GAsyncResult *res,
GError **error);
MbimDevice *mm_mbim_port_peek_device (MMMbimPort *self); MbimDevice *mm_mbim_port_peek_device (MMMbimPort *self);

View File

@@ -345,8 +345,8 @@ port_probe_run_task_free (PortProbeRunTask *task)
#if defined WITH_MBIM #if defined WITH_MBIM
if (task->mbim_port) { if (task->mbim_port) {
if (mm_mbim_port_is_open (task->mbim_port)) /* We should have closed it cleanly before */
mm_mbim_port_close (task->mbim_port); g_assert (!mm_mbim_port_is_open (task->mbim_port));
g_object_unref (task->mbim_port); g_object_unref (task->mbim_port);
} }
#endif #endif
@@ -468,10 +468,23 @@ wdm_probe_qmi (MMPortProbe *self)
#if defined WITH_MBIM #if defined WITH_MBIM
static void
mbim_port_close_ready (MMMbimPort *mbim_port,
GAsyncResult *res,
MMPortProbe *self)
{
PortProbeRunTask *task = self->priv->task;
mm_mbim_port_close_finish (mbim_port, res, NULL);
/* Keep on */
task->source_id = g_idle_add ((GSourceFunc)wdm_probe, self);
}
static void static void
mbim_port_open_ready (MMMbimPort *mbim_port, mbim_port_open_ready (MMMbimPort *mbim_port,
GAsyncResult *res, GAsyncResult *res,
MMPortProbe *self) MMPortProbe *self)
{ {
PortProbeRunTask *task = self->priv->task; PortProbeRunTask *task = self->priv->task;
GError *error = NULL; GError *error = NULL;
@@ -489,10 +502,9 @@ mbim_port_open_ready (MMMbimPort *mbim_port,
/* Set probing result */ /* Set probing result */
mm_port_probe_set_result_mbim (self, is_mbim); mm_port_probe_set_result_mbim (self, is_mbim);
mm_mbim_port_close (mbim_port); mm_mbim_port_close (task->mbim_port,
(GAsyncReadyCallback)mbim_port_close_ready,
/* Keep on */ self);
task->source_id = g_idle_add ((GSourceFunc)wdm_probe, self);
} }
static gboolean static gboolean