void mm_port_probe_run (MMPortProbe *self, MMPortProbeFlag flags, guint64 at_send_delay, const MMPortProbeAtCommand *at_custom_init, GAsyncReadyCallback callback, gpointer user_data) { PortProbeRunTask *task; guint32 i; gchar *probe_list_str; g_return_if_fail (MM_IS_PORT_PROBE (self)); g_return_if_fail (flags != MM_PORT_PROBE_NONE); g_return_if_fail (callback != NULL); /* 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->flags = MM_PORT_PROBE_NONE; task->at_custom_init = at_custom_init; task->result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, mm_port_probe_run); /* Check if we already have the requested probing results. * We will fix here the 'task->flags' so that we only request probing * for the missing things. */ for (i = MM_PORT_PROBE_AT; i <= MM_PORT_PROBE_QCDM; i = (i << 1)) { if ((flags & i) && !(self->priv->flags & i)) { task->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); return; } /* Setup internal cancellable */ task->cancellable = g_cancellable_new (); probe_list_str = mm_port_probe_flag_build_string_from_mask (task->flags); mm_info ("(%s) launching port probing: '%s'", self->priv->name, probe_list_str); 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->at_probing_cancellable = g_cancellable_new (); task->source_id = g_idle_add ((GSourceFunc)serial_open_at, self); return; } /* Otherwise, start by opening as QCDM port */ if (task->flags & MM_PORT_PROBE_QCDM) { task->source_id = g_idle_add ((GSourceFunc)serial_probe_qcdm, self); return; } /* Shouldn't happen */ g_assert_not_reached (); }
void mm_plugin_supports_port (MMPlugin *self, MMDevice *device, GUdevDevice *port, GAsyncReadyCallback callback, gpointer user_data) { MMPortProbe *probe; GSimpleAsyncResult *async_result; PortProbeRunContext *ctx; gboolean need_vendor_probing; gboolean need_product_probing; MMPortProbeFlag probe_run_flags; gchar *probe_list_str; async_result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, mm_plugin_supports_port); /* Apply filters before launching the probing */ if (apply_pre_probing_filters (self, device, port, &need_vendor_probing, &need_product_probing)) { /* Filtered! */ g_simple_async_result_set_op_res_gpointer (async_result, GUINT_TO_POINTER (MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED), NULL); g_simple_async_result_complete_in_idle (async_result); goto out; } /* Need to launch new probing */ probe = MM_PORT_PROBE (mm_device_get_port_probe (device, port)); if (!probe) { /* This may happen if the ports get removed from the device while * probing is ongoing */ g_simple_async_result_set_error (async_result, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "(%s) Missing port probe for port (%s/%s)", self->priv->name, g_udev_device_get_subsystem (port), g_udev_device_get_name (port)); g_simple_async_result_complete_in_idle (async_result); goto out; } /* Before launching any probing, check if the port is a net device. */ if (g_str_equal (g_udev_device_get_subsystem (port), "net")) { mm_dbg ("(%s) [%s] probing deferred until result suggested", self->priv->name, g_udev_device_get_name (port)); g_simple_async_result_set_op_res_gpointer ( async_result, GUINT_TO_POINTER (MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED), NULL); g_simple_async_result_complete_in_idle (async_result); goto out; } /* Build flags depending on what probing needed */ if (!g_str_has_prefix (g_udev_device_get_name (port), "cdc-wdm")) { /* Serial ports... */ probe_run_flags = MM_PORT_PROBE_NONE; if (self->priv->at) probe_run_flags |= MM_PORT_PROBE_AT; else if (self->priv->single_at) probe_run_flags |= MM_PORT_PROBE_AT; if (need_vendor_probing) probe_run_flags |= (MM_PORT_PROBE_AT | MM_PORT_PROBE_AT_VENDOR); if (need_product_probing) probe_run_flags |= (MM_PORT_PROBE_AT | MM_PORT_PROBE_AT_PRODUCT); if (self->priv->qcdm) probe_run_flags |= MM_PORT_PROBE_QCDM; if (self->priv->icera_probe || self->priv->allowed_icera || self->priv->forbidden_icera) probe_run_flags |= (MM_PORT_PROBE_AT | MM_PORT_PROBE_AT_ICERA); } else { /* cdc-wdm ports... */ probe_run_flags = MM_PORT_PROBE_QMI; } g_assert (probe_run_flags != MM_PORT_PROBE_NONE); /* If a modem is already available and the plugin says that only one AT port is * expected, check if we alredy got the single AT port. And if so, we know this * port being probed won't be AT. */ if (self->priv->single_at && mm_port_probe_list_has_at_port (mm_device_peek_port_probe_list (device)) && !mm_port_probe_is_at (probe)) { mm_dbg ("(%s) [%s] not setting up AT probing tasks: " "modem already has the expected single AT port", self->priv->name, g_udev_device_get_name (port)); /* Assuming it won't be an AT port. We still run the probe anyway, in * case we need to check for other port types (e.g. QCDM) */ mm_port_probe_set_result_at (probe, FALSE); } /* Setup async call context */ ctx = g_new (PortProbeRunContext, 1); ctx->self = g_object_ref (self); ctx->device = g_object_ref (device); ctx->result = g_object_ref (async_result); ctx->flags = probe_run_flags; /* Launch the probe */ probe_list_str = mm_port_probe_flag_build_string_from_mask (ctx->flags); mm_dbg ("(%s) [%s] probe required: '%s'", self->priv->name, g_udev_device_get_name (port), probe_list_str); g_free (probe_list_str); mm_port_probe_run (probe, ctx->flags, self->priv->send_delay, self->priv->remove_echo, self->priv->custom_at_probe, self->priv->custom_init, (GAsyncReadyCallback)port_probe_run_ready, ctx); out: g_object_unref (async_result); }