示例#1
0
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);
}
示例#2
0
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);
}
示例#8
0
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);
}
示例#9
0
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);
}
示例#10
0
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);
}
示例#11
0
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);
}