Esempio n. 1
0
static gboolean
wdm_probe_qmi (MMPortProbe *self)
{
    PortProbeRunTask *task = self->priv->task;

    /* If already cancelled, do nothing else */
    if (port_probe_run_is_cancelled (self))
        return FALSE;

#if defined WITH_QMI
    mm_dbg ("(%s/%s) probing QMI...",
            g_udev_device_get_subsystem (self->priv->port),
            g_udev_device_get_name (self->priv->port));

    /* Create a port and try to open it */
    task->qmi_port = mm_qmi_port_new (g_udev_device_get_name (self->priv->port));
    mm_qmi_port_open (task->qmi_port,
                      FALSE,
                      NULL,
                      (GAsyncReadyCallback)qmi_port_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);
    port_probe_run_task_complete (task, TRUE, NULL);
#endif /* WITH_QMI */

    return FALSE;
}
Esempio n. 2
0
static gboolean
serial_probe_at (MMPortProbe *self)
{
    PortProbeRunTask *task = self->priv->task;

    task->source_id = 0;

    /* If already cancelled, do nothing else */
    if (port_probe_run_is_cancelled (self))
        return FALSE;

    /* If AT probing cancelled, end this partial probing */
    if (g_cancellable_is_cancelled (task->at_probing_cancellable)) {
        mm_dbg ("(%s) no need to launch probing for AT support",
                self->priv->name);
        task->at_result_processor (self, NULL);
        serial_probe_schedule (self);
        return FALSE;
    }

    mm_at_serial_port_queue_command (
        MM_AT_SERIAL_PORT (task->serial),
        task->at_commands->command,
        task->at_commands->timeout,
        task->at_probing_cancellable,
        (MMAtSerialResponseFn)serial_probe_at_parse_response,
        self);
    return FALSE;
}
Esempio n. 3
0
static void
serial_probe_schedule (MMPortProbe *self)
{
    PortProbeRunTask *task = self->priv->task;

    /* If already cancelled, do nothing else */
    if (port_probe_run_is_cancelled (self))
        return;

    /* Cleanup */
    task->at_result_processor = NULL;
    task->at_commands = NULL;

    /* If we got some custom initialization commands requested, go on with them
     * first. */
    if (task->at_custom_init) {
        task->at_result_processor = serial_probe_at_custom_init_result_processor;
        task->at_commands = task->at_custom_init;
    }
    /* AT check requested and not already probed? */
    else if ((task->flags & MM_PORT_PROBE_AT) &&
             !(self->priv->flags & MM_PORT_PROBE_AT)) {
        /* Prepare AT probing */
        task->at_result_processor = serial_probe_at_result_processor;
        task->at_commands = at_probing;
    }
    /* Vendor requested and not already probed? */
    else if ((task->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;
    }
    /* Product requested and not already probed? */
    else if ((task->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;
    }

    /* 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);
        return;
    }

    /* QCDM requested and not already probed? */
    if ((task->flags & MM_PORT_PROBE_QCDM) &&
        !(self->priv->flags & MM_PORT_PROBE_QCDM)) {
        task->source_id = g_idle_add ((GSourceFunc)serial_probe_qcdm, self);
        return;
    }

    /* All done! Finish asynchronously */
    port_probe_run_task_complete (task, TRUE, NULL);
}
Esempio n. 4
0
static void
serial_probe_qcdm_parse_response (MMQcdmSerialPort *port,
                                  GByteArray *response,
                                  GError *error,
                                  MMPortProbe *self)
{
    QcdmResult *result;
    gint err = QCDM_SUCCESS;
    gboolean is_qcdm = FALSE;

    /* Just the initial poke; ignore it */
    if (!self)
        return;

    /* If already cancelled, do nothing else */
    if (port_probe_run_is_cancelled (self))
        return;

    if (!error) {
        /* Parse the response */
        result = qcdm_cmd_version_info_result ((const gchar *) response->data,
                                               response->len,
                                               &err);
        if (!result) {
            mm_warn ("(%s) failed to parse QCDM version info command result: %d",
                     self->priv->name,
                     err);
        } else {
            /* yay, probably a QCDM port */
            is_qcdm = TRUE;

            qcdm_result_unref (result);
        }
    }

    /* Set probing result */
    mm_port_probe_set_result_qcdm (self, is_qcdm);

    /* Reschedule probing */
    serial_probe_schedule (self);
}
Esempio n. 5
0
static gboolean
serial_open_at (MMPortProbe *self)
{
    PortProbeRunTask *task = self->priv->task;
    GError *error = NULL;

    task->source_id = 0;

    /* If already cancelled, do nothing else */
    if (port_probe_run_is_cancelled (self))
        return FALSE;

    /* Create AT serial port if not done before */
    if (!task->serial) {
        task->serial = MM_SERIAL_PORT (mm_at_serial_port_new (self->priv->name));
        if (!task->serial) {
            port_probe_run_task_complete (
                task,
                FALSE,
                g_error_new (MM_CORE_ERROR,
                             MM_CORE_ERROR_FAILED,
                             "(%s) couldn't create AT port",
                             self->priv->name));
            return FALSE;
        }

        g_object_set (task->serial,
                      MM_SERIAL_PORT_SEND_DELAY, task->at_send_delay,
                      MM_PORT_CARRIER_DETECT, FALSE,
                      MM_SERIAL_PORT_SPEW_CONTROL, TRUE,
                      NULL);

        mm_at_serial_port_set_response_parser (MM_AT_SERIAL_PORT (task->serial),
                                               mm_serial_parser_v1_parse,
                                               mm_serial_parser_v1_new (),
                                               mm_serial_parser_v1_destroy);
    }

    /* Try to open the port */
    if (!mm_serial_port_open (task->serial, &error)) {
        /* Abort if maximum number of open tries reached */
        if (++task->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) failed to open port after 4 tries",
                             self->priv->name));
        } else 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) failed to open port: %s",
                             self->priv->name,
                             (error ? error->message : "unknown error")));
        }

        g_clear_error (&error);
        return FALSE;
    }

    /* success, start probing */
    task->buffer_full_id = g_signal_connect (task->serial,
                                             "buffer-full",
                                             G_CALLBACK (serial_buffer_full),
                                             self);

    mm_serial_port_flash (MM_SERIAL_PORT (task->serial),
                          100,
                          TRUE,
                          (MMSerialFlashFn)serial_flash_done,
                          self);
    return FALSE;
}
Esempio n. 6
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) no need to keep on probing the port for AT support",
                self->priv->name);
        task->at_result_processor (self, NULL);
        serial_probe_schedule (self);
        return;
    }

    if (!task->at_commands->response_processor (task->at_commands->command,
                                                response->str,
                                                !!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) error while probing AT features: %s",
                             self->priv->name,
                             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);
}
Esempio n. 7
0
static gboolean
serial_probe_qcdm (MMPortProbe *self)
{
    PortProbeRunTask *task = self->priv->task;
    GError *error = NULL;
    GByteArray *verinfo = NULL;
    GByteArray *verinfo2;
    gint len;

    task->source_id = 0;

    /* If already cancelled, do nothing else */
    if (port_probe_run_is_cancelled (self))
        return FALSE;

    mm_dbg ("(%s) probing QCDM...", self->priv->name);

    /* If open, close the AT port */
    if (task->serial) {
        mm_serial_port_close (task->serial);
        g_object_unref (task->serial);
    }

    /* Open the QCDM port */
    task->serial = MM_SERIAL_PORT (mm_qcdm_serial_port_new (self->priv->name));
    if (!task->serial) {
        port_probe_run_task_complete (
            task,
            FALSE,
            g_error_new (MM_CORE_ERROR,
                         MM_CORE_ERROR_FAILED,
                         "(%s) Couldn't create QCDM port",
                         self->priv->name));
        return FALSE;
    }

    /* Try to open the port */
    if (!mm_serial_port_open (task->serial, &error)) {
        port_probe_run_task_complete (
            task,
            FALSE,
            g_error_new (MM_SERIAL_ERROR,
                         MM_SERIAL_ERROR_OPEN_FAILED,
                         "(%s) Failed to open QCDM port: %s",
                         self->priv->name,
                         (error ? error->message : "unknown error")));
        g_clear_error (&error);
        return FALSE;
    }

    /* Build up the probe command */
    verinfo = g_byte_array_sized_new (50);
    len = qcdm_cmd_version_info_new ((gchar *) verinfo->data, 50);
    if (len <= 0) {
        g_byte_array_free (verinfo, TRUE);
        port_probe_run_task_complete (
            task,
            FALSE,
            g_error_new (MM_SERIAL_ERROR,
                         MM_SERIAL_ERROR_OPEN_FAILED,
                         "(%s) Failed to create QCDM versin info command",
                         self->priv->name));
        return FALSE;
    }
    verinfo->len = len;

    /* Queuing the command takes ownership over it; dup it for the second try */
    verinfo2 = g_byte_array_sized_new (verinfo->len);
    g_byte_array_append (verinfo2, verinfo->data, verinfo->len);

    /* Send the command twice; the ports often need to be woken up */
    mm_qcdm_serial_port_queue_command (MM_QCDM_SERIAL_PORT (task->serial),
                                       verinfo,
                                       3,
                                       NULL,
                                       (MMQcdmSerialResponseFn)serial_probe_qcdm_parse_response,
                                       NULL);
    mm_qcdm_serial_port_queue_command (MM_QCDM_SERIAL_PORT (task->serial),
                                       verinfo2,
                                       3,
                                       NULL,
                                       (MMQcdmSerialResponseFn)serial_probe_qcdm_parse_response,
                                       self);

    return FALSE;
}
Esempio n. 8
0
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;

    task->source_id = 0;

    /* If already cancelled, do nothing else */
    if (port_probe_run_is_cancelled (self))
        return FALSE;

    mm_dbg ("(%s/%s) probing QCDM...",
            g_udev_device_get_subsystem (self->priv->port),
            g_udev_device_get_name (self->priv->port));

    /* If open, close the AT port */
    if (task->serial) {
        mm_serial_port_close (task->serial);
        g_object_unref (task->serial);
    }

    /* Open the QCDM port */
    task->serial = MM_SERIAL_PORT (mm_qcdm_serial_port_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)));
        return FALSE;
    }

    /* Try to open the port */
    if (!mm_serial_port_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")));
        g_clear_error (&error);
        return FALSE;
    }

    /* Build up the probe command; 0x7E is the frame marker, so put one at the
     * beginning of the buffer to ensure that the device discards any AT
     * commands that probing might have sent earlier.  Should help devices
     * respond more quickly and speed up QCDM probing.
     */
    verinfo = g_byte_array_sized_new (10);
    g_byte_array_append (verinfo, &marker, 1);
    len = qcdm_cmd_version_info_new ((char *) (verinfo->data + 1), 9);
    if (len <= 0) {
        g_byte_array_free (verinfo, TRUE);
        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)));
        return FALSE;
    }
    verinfo->len = len + 1;

    /* Queuing the command takes ownership over it; save it for the second try */
    verinfo2 = g_byte_array_sized_new (verinfo->len);
    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_qcdm_serial_port_queue_command (MM_QCDM_SERIAL_PORT (task->serial),
                                       verinfo,
                                       3,
                                       NULL,
                                       (MMQcdmSerialResponseFn)serial_probe_qcdm_parse_response,
                                       self);

    return FALSE;
}
Esempio n. 9
0
static void
serial_probe_qcdm_parse_response (MMQcdmSerialPort *port,
                                  GByteArray *response,
                                  GError *error,
                                  MMPortProbe *self)
{
    QcdmResult *result;
    gint err = QCDM_SUCCESS;
    gboolean is_qcdm = FALSE;
    gboolean retry = FALSE;
    PortProbeRunTask *task = self->priv->task;

    /* If already cancelled, do nothing else */
    if (port_probe_run_is_cancelled (self))
        return;

    if (!error) {
        /* Parse the response */
        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),
                     g_udev_device_get_name (self->priv->port),
                     err);
            retry = TRUE;
        } else {
            /* yay, probably a QCDM port */
            is_qcdm = TRUE;

            qcdm_result_unref (result);
        }
    } 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);
        retry = TRUE;
    }

    if (retry) {
        GByteArray *cmd2;

        cmd2 = g_object_steal_data (G_OBJECT (self), "cmd2");
        if (cmd2) {
            /* second try */
            mm_qcdm_serial_port_queue_command (MM_QCDM_SERIAL_PORT (task->serial),
                                               cmd2,
                                               3,
                                               NULL,
                                               (MMQcdmSerialResponseFn)serial_probe_qcdm_parse_response,
                                               self);
            return;
        }

        /* no more retries left */
    }

    /* Set probing result */
    mm_port_probe_set_result_qcdm (self, is_qcdm);

    /* Reschedule probing */
    serial_probe_schedule (self);
}