static void serial_probe_at_result_processor (MMPortProbe *self, GVariant *result) { if (result) { /* If any result given, it must be a boolean */ g_assert (g_variant_is_of_type (result, G_VARIANT_TYPE_BOOLEAN)); if (g_variant_get_boolean (result)) { mm_port_probe_set_result_at (self, TRUE); return; } } mm_port_probe_set_result_at (self, FALSE); }
static void serial_buffer_full (MMSerialPort *serial, GByteArray *buffer, MMPortProbe *self) { if (is_non_at_response (buffer->data, buffer->len)) { mm_serial_port_close (serial); mm_port_probe_set_result_at (self, FALSE); serial_probe_schedule (self); } }
static void getportmode_ready (MMPortSerialAt *port, GAsyncResult *res, HuaweiCustomInitContext *ctx) { const gchar *response; GError *error = NULL; response = mm_port_serial_at_command_finish (port, res, &error); if (error) { mm_dbg ("(Huawei) couldn't get port mode: '%s'", error->message); /* If any error occurred that was not ERROR or COMMAND NOT SUPPORT then * retry the command. */ if (!g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN)) goto out; /* Port mode not supported */ } else { MMDevice *device; mm_dbg ("(Huawei) port mode layout retrieved"); /* Results are cached in the parent device object */ device = mm_port_probe_peek_device (ctx->probe); cache_port_mode (device, response, "PCUI:", TAG_HUAWEI_PCUI_PORT); cache_port_mode (device, response, "MDM:", TAG_HUAWEI_MODEM_PORT); cache_port_mode (device, response, "NDIS:", TAG_HUAWEI_NDIS_PORT); cache_port_mode (device, response, "DIAG:", TAG_HUAWEI_DIAG_PORT); /* GETPORTMODE response format in newer devices... (e.g. E3372) */ cache_port_mode (device, response, "pcui:", TAG_HUAWEI_PCUI_PORT); cache_port_mode (device, response, "modem:", TAG_HUAWEI_MODEM_PORT); g_object_set_data (G_OBJECT (device), TAG_GETPORTMODE_SUPPORTED, GUINT_TO_POINTER (TRUE)); /* Mark port as being AT already */ mm_port_probe_set_result_at (ctx->probe, TRUE); } ctx->getportmode_done = TRUE; out: if (error) g_error_free (error); huawei_custom_init_step (ctx); }
static void gcap_ready (MMAtSerialPort *port, GString *response, GError *error, SierraCustomInitContext *ctx) { if (error) { /* Just retry... */ sierra_custom_init_step (ctx); return; } /* A valid reply to ATI tells us this is an AT port already */ mm_port_probe_set_result_at (ctx->probe, TRUE); /* Sierra APPx ports have limited AT command parsers that just reply with * "OK" to most commands. These can sometimes be used for PPP while the * main port is used for status and control, but older modems tend to crash * or fail PPP. So we whitelist modems that are known to allow PPP on the * secondary APP ports. */ if (strstr (response->str, "APP1")) { g_object_set_data (G_OBJECT (ctx->probe), TAG_SIERRA_APP_PORT, GUINT_TO_POINTER (TRUE)); /* PPP-on-APP1-port whitelist */ if (strstr (response->str, "C885") || strstr (response->str, "USB 306")) g_object_set_data (G_OBJECT (ctx->probe), TAG_SIERRA_APP1_PPP_OK, GUINT_TO_POINTER (TRUE)); /* For debugging: let users figure out if their device supports PPP * on the APP1 port or not. */ if (getenv ("MM_SIERRA_APP1_PPP_OK")) { mm_dbg ("Sierra: APP1 PPP OK '%s'", response->str); g_object_set_data (G_OBJECT (ctx->probe), TAG_SIERRA_APP1_PPP_OK, GUINT_TO_POINTER (TRUE)); } } else if (strstr (response->str, "APP2") || strstr (response->str, "APP3") || strstr (response->str, "APP4")) { /* Additional APP ports don't support most AT commands, so they cannot * be used as the primary port. */ g_object_set_data (G_OBJECT (ctx->probe), TAG_SIERRA_APP_PORT, GUINT_TO_POINTER (TRUE)); } g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); sierra_custom_init_context_complete_and_free (ctx); }
static void getportcfg_ready (MMPortSerialAt *port, GAsyncResult *res, TelitCustomInitContext *ctx) { const gchar *response; GError *error = NULL; response = mm_port_serial_at_command_finish (port, res, &error); if (error) { mm_dbg ("telit: couldn't get port mode: '%s'", error->message); /* If ERROR or COMMAND NOT SUPPORT occur then do not retry the * command. */ if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN)) ctx->getportcfg_done = TRUE; } else { MMDevice *device; device = mm_port_probe_peek_device (ctx->probe); /* Results are cached in the parent device object */ if (g_object_get_data (G_OBJECT (device), TAG_GETPORTCFG_SUPPORTED) == NULL) { mm_dbg ("telit: retrieving port mode layout"); if (cache_port_mode (device, response)) { g_object_set_data (G_OBJECT (device), TAG_GETPORTCFG_SUPPORTED, GUINT_TO_POINTER (TRUE)); ctx->getportcfg_done = TRUE; } } /* Port answered to #PORTCFG, so mark it as being AT already */ mm_port_probe_set_result_at (ctx->probe, TRUE); } if (error) g_error_free (error); telit_custom_init_step (ctx); }
static void getportmode_ready (MMAtSerialPort *port, GString *response, GError *error, HuaweiCustomInitContext *ctx) { if (error) { mm_dbg ("(Huawei) couldn't get port mode: '%s'", error->message); /* If any error occurred that was not ERROR or COMMAND NOT SUPPORT then * retry the command. */ if (!g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN)) { /* Retry */ huawei_custom_init_step (ctx); return; } /* Port mode not supported */ } else { MMDevice *device; mm_dbg ("(Huawei) port mode layout retrieved"); /* Results are cached in the parent device object */ device = mm_port_probe_peek_device (ctx->probe); cache_port_mode (device, response->str, "PCUI:", TAG_HUAWEI_PCUI_PORT); cache_port_mode (device, response->str, "MDM:", TAG_HUAWEI_MODEM_PORT); cache_port_mode (device, response->str, "NDIS:", TAG_HUAWEI_NDIS_PORT); cache_port_mode (device, response->str, "DIAG:", TAG_HUAWEI_DIAG_PORT); g_object_set_data (G_OBJECT (device), TAG_GETPORTMODE_SUPPORTED, GUINT_TO_POINTER (TRUE)); /* Mark port as being AT already */ mm_port_probe_set_result_at (ctx->probe, TRUE); } ctx->getportmode_done = TRUE; huawei_custom_init_step (ctx); }
static void huawei_custom_init_step (HuaweiCustomInitContext *ctx) { FirstInterfaceContext *fi_ctx; /* If cancelled, end */ if (g_cancellable_is_cancelled (ctx->cancellable)) { mm_dbg ("(Huawei) no need to keep on running custom init in (%s)", mm_port_get_device (MM_PORT (ctx->port))); g_simple_async_result_set_error (ctx->result, MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, "Custom initialization cancelled"); huawei_custom_init_context_complete_and_free (ctx); return; } if (!ctx->curc_done) { if (ctx->curc_retries == 0) { /* All retries consumed, probably not an AT port */ mm_port_probe_set_result_at (ctx->probe, FALSE); g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); /* Try with next */ try_next_usbif (mm_port_probe_peek_device (ctx->probe)); huawei_custom_init_context_complete_and_free (ctx); return; } ctx->curc_retries--; /* Turn off unsolicited messages on secondary ports until needed */ mm_at_serial_port_queue_command ( ctx->port, "AT^CURC=0", 3, FALSE, /* raw */ ctx->cancellable, (MMAtSerialResponseFn)curc_ready, ctx); return; } /* Try to get a port map from the modem */ if (!ctx->getportmode_done) { if (ctx->getportmode_retries == 0) { g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); huawei_custom_init_context_complete_and_free (ctx); return; } ctx->getportmode_retries--; mm_at_serial_port_queue_command ( ctx->port, "AT^GETPORTMODE", 3, FALSE, /* raw */ ctx->cancellable, (MMAtSerialResponseFn)getportmode_ready, ctx); return; } /* All done it seems */ fi_ctx = g_object_get_data (G_OBJECT (mm_port_probe_peek_device (ctx->probe)), TAG_FIRST_INTERFACE_CONTEXT); g_assert (fi_ctx != NULL); fi_ctx->custom_init_run = TRUE; g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); huawei_custom_init_context_complete_and_free (ctx); }
static void serial_probe_at_parse_response (MMAtSerialPort *port, GString *response, GError *error, MMPortProbe *self) { PortProbeRunTask *task = self->priv->task; GVariant *result = NULL; GError *result_error = NULL; /* If already cancelled, do nothing else */ if (port_probe_run_is_cancelled (self)) return; /* If AT probing cancelled, end this partial probing */ if (g_cancellable_is_cancelled (task->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); serial_probe_schedule (self); return; } /* Early-abort AT probing if we get a response that indicates this is * certainly not an AT-capable port. */ if (response && is_non_at_response ((const guint8 *) response->str, response->len)) { task->at_result_processor (self, NULL); mm_port_probe_set_result_at (self, FALSE); serial_probe_schedule (self); return; } if (!task->at_commands->response_processor (task->at_commands->command, response ? response->str : NULL, !!task->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)); g_error_free (result_error); return; } /* Go on to next command */ task->at_commands++; if (!task->at_commands->command) { /* Was it the last command in the group? If so, * end this partial probing */ task->at_result_processor (self, NULL); /* Reschedule */ serial_probe_schedule (self); return; } /* Schedule the next command in the probing group */ task->source_id = g_idle_add ((GSourceFunc)serial_probe_at, self); return; } /* Run result processor. * Note that custom init commands are allowed to not return anything */ task->at_result_processor (self, result); if (result) g_variant_unref (result); /* Reschedule probing */ serial_probe_schedule (self); }
static void custom_init_step (CustomInitContext *ctx) { /* If cancelled, end */ if (g_cancellable_is_cancelled (ctx->cancellable)) { mm_dbg ("(Dell) 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 defined WITH_QMI /* If device has a QMI port, don't run anything else, as we don't care */ if (mm_port_probe_list_has_qmi_port (mm_device_peek_port_probe_list (mm_port_probe_peek_device (ctx->probe)))) { mm_dbg ("(Dell) no need to run custom init in (%s): device has QMI port", mm_port_get_device (MM_PORT (ctx->port))); mm_port_probe_set_result_at (ctx->probe, FALSE); mm_port_probe_set_result_qcdm (ctx->probe, FALSE); g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); custom_init_context_complete_and_free (ctx); return; } #endif #if defined WITH_MBIM /* If device has a MBIM port, don't run anything else, as we don't care */ if (mm_port_probe_list_has_mbim_port (mm_device_peek_port_probe_list (mm_port_probe_peek_device (ctx->probe)))) { mm_dbg ("(Dell) no need to run custom init in (%s): device has MBIM port", mm_port_get_device (MM_PORT (ctx->port))); mm_port_probe_set_result_at (ctx->probe, FALSE); mm_port_probe_set_result_qcdm (ctx->probe, FALSE); g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); custom_init_context_complete_and_free (ctx); return; } #endif if (ctx->gmi_retries > 0) { ctx->gmi_retries--; mm_port_serial_at_command (ctx->port, "AT+GMI", 3, FALSE, /* raw */ FALSE, /* allow_cached */ ctx->cancellable, (GAsyncReadyCallback)response_ready, ctx); return; } if (ctx->cgmi_retries > 0) { ctx->cgmi_retries--; mm_port_serial_at_command (ctx->port, "AT+CGMI", 3, FALSE, /* raw */ FALSE, /* allow_cached */ ctx->cancellable, (GAsyncReadyCallback)response_ready, ctx); return; } if (ctx->ati_retries > 0) { ctx->ati_retries--; /* Note: in Ericsson devices, ATI3 seems to reply the vendor string */ mm_port_serial_at_command (ctx->port, "ATI1I2I3", 3, FALSE, /* raw */ FALSE, /* allow_cached */ ctx->cancellable, (GAsyncReadyCallback)response_ready, ctx); return; } /* Finish custom_init */ mm_dbg ("(Dell) 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 huawei_custom_init_step (HuaweiCustomInitContext *ctx) { FirstInterfaceContext *fi_ctx; GUdevDevice *port; /* If cancelled, end */ if (g_cancellable_is_cancelled (ctx->cancellable)) { mm_dbg ("(Huawei) 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); huawei_custom_init_context_complete_and_free (ctx); return; } if (!ctx->curc_done) { if (ctx->curc_retries == 0) { /* All retries consumed, probably not an AT port */ mm_port_probe_set_result_at (ctx->probe, FALSE); g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); /* Try with next */ try_next_usbif (mm_port_probe_peek_device (ctx->probe)); huawei_custom_init_context_complete_and_free (ctx); return; } ctx->curc_retries--; /* Turn off unsolicited messages on secondary ports until needed */ mm_port_serial_at_command ( ctx->port, "AT^CURC=0", 3, FALSE, /* raw */ FALSE, /* allow_cached */ ctx->cancellable, (GAsyncReadyCallback)curc_ready, ctx); return; } /* Try to get a port map from the modem */ port = mm_port_probe_peek_port (ctx->probe); if (!ctx->getportmode_done && !g_udev_device_get_property_as_boolean (port, "ID_MM_HUAWEI_DISABLE_GETPORTMODE")) { if (ctx->getportmode_retries == 0) { g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); huawei_custom_init_context_complete_and_free (ctx); return; } ctx->getportmode_retries--; mm_port_serial_at_command ( ctx->port, "AT^GETPORTMODE", 3, FALSE, /* raw */ FALSE, /* allow_cached */ ctx->cancellable, (GAsyncReadyCallback)getportmode_ready, ctx); return; } /* All done it seems */ fi_ctx = g_object_get_data (G_OBJECT (mm_port_probe_peek_device (ctx->probe)), TAG_FIRST_INTERFACE_CONTEXT); g_assert (fi_ctx != NULL); fi_ctx->custom_init_run = TRUE; g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); huawei_custom_init_context_complete_and_free (ctx); }
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); }