예제 #1
0
static gboolean
handle_set_profile (MmGdbusTest *skeleton,
                    GDBusMethodInvocation *invocation,
                    const gchar *id,
                    const gchar *plugin_name,
                    const gchar *const *ports,
                    MMBaseManager *self)
{
    MMPlugin *plugin;
    MMDevice *device;
    gchar *physdev;
    GError *error = NULL;

    mm_info ("Test profile set to: '%s'", id);

    /* Create device and keep it listed in the Manager */
    physdev = g_strdup_printf ("/virtual/%s", id);
    device = mm_device_virtual_new (physdev, TRUE);
    g_hash_table_insert (self->priv->devices, physdev, device);

    /* Grab virtual ports */
    mm_device_virtual_grab_ports (device, (const gchar **)ports);

    /* Set plugin to use */
    plugin = mm_plugin_manager_peek_plugin (self->priv->plugin_manager, plugin_name);
    if (!plugin) {
        error = g_error_new (MM_CORE_ERROR,
                             MM_CORE_ERROR_NOT_FOUND,
                             "Requested plugin '%s' not found",
                             plugin_name);
        mm_warn ("Couldn't set plugin for virtual device at '%s': %s",
                 mm_device_get_path (device),
                 error->message);
        goto out;
    }
    mm_device_set_plugin (device, G_OBJECT (plugin));

    /* Create modem */
    if (!mm_device_create_modem (device, self->priv->object_manager, &error)) {
        mm_warn ("Couldn't create modem for virtual device at '%s': %s",
                 mm_device_get_path (device),
                 error->message);
        goto out;
    }

    mm_info ("Modem for virtual device at '%s' successfully created",
             mm_device_get_path (device));

out:

    if (error) {
        mm_device_remove_modem (device);
        g_hash_table_remove (self->priv->devices, mm_device_get_path (device));
        g_dbus_method_invocation_return_gerror (invocation, error);
        g_error_free (error);
    } else
        mm_gdbus_test_complete_set_profile (skeleton, invocation);

    return TRUE;
}
예제 #2
0
static MMPlugin *
load_plugin (const gchar *path)
{
    MMPlugin *plugin = NULL;
    GModule *module;
    MMPluginCreateFunc plugin_create_func;
    gint *major_plugin_version;
    gint *minor_plugin_version;
    gchar *path_display;

    /* Get printable UTF-8 string of the path */
    path_display = g_filename_display_name (path);

    module = g_module_open (path, G_MODULE_BIND_LAZY);
    if (!module) {
        g_warning ("Could not load plugin '%s': %s", path_display, g_module_error ());
        goto out;
    }

    if (!g_module_symbol (module, "mm_plugin_major_version", (gpointer *) &major_plugin_version)) {
        g_warning ("Could not load plugin '%s': Missing major version info", path_display);
        goto out;
    }

    if (*major_plugin_version != MM_PLUGIN_MAJOR_VERSION) {
        g_warning ("Could not load plugin '%s': Plugin major version %d, %d is required",
                   path_display, *major_plugin_version, MM_PLUGIN_MAJOR_VERSION);
        goto out;
    }

    if (!g_module_symbol (module, "mm_plugin_minor_version", (gpointer *) &minor_plugin_version)) {
        g_warning ("Could not load plugin '%s': Missing minor version info", path_display);
        goto out;
    }

    if (*minor_plugin_version != MM_PLUGIN_MINOR_VERSION) {
        g_warning ("Could not load plugin '%s': Plugin minor version %d, %d is required",
                   path_display, *minor_plugin_version, MM_PLUGIN_MINOR_VERSION);
        goto out;
    }

    if (!g_module_symbol (module, "mm_plugin_create", (gpointer *) &plugin_create_func)) {
        g_warning ("Could not load plugin '%s': %s", path_display, g_module_error ());
        goto out;
    }

    plugin = (*plugin_create_func) ();
    if (plugin) {
        g_object_weak_ref (G_OBJECT (plugin), (GWeakNotify) g_module_close, module);
    } else
        mm_warn ("Could not load plugin '%s': initialization failed", path_display);

out:
    if (module && !plugin)
        g_module_close (module);

    g_free (path_display);

    return plugin;
}
void
mm_port_qmi_close (MMPortQmi *self)
{
    GList *l;
    GError *error = NULL;

    g_return_if_fail (MM_IS_PORT_QMI (self));

    if (!self->priv->qmi_device)
        return;

    /* Release all allocated clients */
    for (l = self->priv->services; l; l = g_list_next (l)) {
        ServiceInfo *info = l->data;

        mm_dbg ("Releasing client for service '%s'...", qmi_service_get_string (info->service));
        qmi_device_release_client (self->priv->qmi_device,
                                   info->client,
                                   QMI_DEVICE_RELEASE_CLIENT_FLAGS_RELEASE_CID,
                                   3, NULL, NULL, NULL);
        g_clear_object (&info->client);
    }
    g_list_free_full (self->priv->services, (GDestroyNotify)g_free);
    self->priv->services = NULL;

    /* Close and release the device */
    if (!qmi_device_close (self->priv->qmi_device, &error)) {
        mm_warn ("Couldn't properly close QMI device: %s",
                 error->message);
        g_error_free (error);
    }

    g_clear_object (&self->priv->qmi_device);
}
예제 #4
0
static void
initialize_ready (MMBaseModem *self,
                  GAsyncResult *res)
{
    GError *error = NULL;

    if (mm_base_modem_initialize_finish (self, res, &error)) {
        mm_dbg ("modem properly initialized");
        mm_base_modem_set_valid (self, TRUE);
        return;
    }

    /* Wrong state is returned when modem is found locked */
    if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE)) {
        /* Even with initialization errors, we do set the state to valid, so
         * that the modem gets exported and the failure notified to the user.
         */
        mm_dbg ("Couldn't finish initialization in the current state: '%s'",
                error->message);
        g_error_free (error);
        mm_base_modem_set_valid (self, TRUE);
        return;
    }

    /* Really fatal, we cannot even export the failed modem (e.g. error before
     * even trying to enable the Modem interface */
    mm_warn ("couldn't initialize the modem: '%s'", error->message);
    g_error_free (error);
}
static void
emrdy_ready (MMBaseModem *self,
             GAsyncResult *res,
             EnablingModemInitContext *ctx)
{
    GError *error = NULL;

    /* EMRDY unsolicited response might have happened between the command
     * submission and the response.  This was seen once:
     *
     * (ttyACM0): --> 'AT*EMRDY?<CR>'
     * (ttyACM0): <-- 'T*EMRD<CR><LF>*EMRDY: 1<CR><LF>Y?'
     *
     * So suppress the warning if the unsolicited handler handled the response
     * before we get here.
     */
    if (!mm_base_modem_at_command_finish (self, res, &error)) {
        if (g_error_matches (error,
                             MM_SERIAL_ERROR,
                             MM_SERIAL_ERROR_RESPONSE_TIMEOUT))
            mm_warn ("timed out waiting for EMRDY response.");
        else
            ctx->self->priv->have_emrdy = TRUE;
        g_error_free (error);
    }

    run_enabling_init_sequence (ctx);
}
예제 #6
0
static void
device_support_check_ready (MMPluginManager          *plugin_manager,
                            GAsyncResult             *res,
                            FindDeviceSupportContext *ctx)
{
    GError   *error = NULL;
    MMPlugin *plugin;

    /* Receive plugin result from the plugin manager */
    plugin = mm_plugin_manager_device_support_check_finish (plugin_manager, res, &error);
    if (!plugin) {
        mm_info ("Couldn't check support for device at '%s': %s",
                 mm_device_get_path (ctx->device), error->message);
        g_error_free (error);
        find_device_support_context_free (ctx);
        return;
    }

    /* Set the plugin as the one expected in the device */
    mm_device_set_plugin (ctx->device, G_OBJECT (plugin));
    g_object_unref (plugin);

    if (!mm_device_create_modem (ctx->device, ctx->self->priv->object_manager, &error)) {
        mm_warn ("Couldn't create modem for device at '%s': %s",
                 mm_device_get_path (ctx->device), error->message);
        g_error_free (error);
        find_device_support_context_free (ctx);
        return;
    }

    /* Modem now created */
    mm_info ("Modem for device at '%s' successfully created",
             mm_device_get_path (ctx->device));
    find_device_support_context_free (ctx);
}
static void
connect_3gpp_qmiconnect_ready (MMBaseModem *modem,
                               GAsyncResult *res,
                               DetailedConnectContext *ctx)
{
    const gchar *result;
    GError *error = NULL;

    result = mm_base_modem_at_command_finish (MM_BASE_MODEM (modem),
                                              res,
                                              &error);
    if (!result) {
        mm_warn ("QMI connection failed: %s", error->message);
        g_simple_async_result_take_error (ctx->result, error);
        detailed_connect_context_complete_and_free (ctx);
        return;
    }

    /*
     * The connection takes a bit of time to set up, but there's no
     * asynchronous notification from the modem when this has
     * happened. Instead, we need to poll the modem to see if it's
     * ready.
     */
    g_timeout_add_seconds(1, (GSourceFunc)connect_3gpp_qmistatus, ctx);
}
예제 #8
0
static void
name_lost_cb (GDBusConnection *connection,
              const gchar *name,
              gpointer user_data)
{
    /* Note that we're not allowing replacement, so once the name acquired, the
     * process won't lose it. */
    if (!name)
        mm_warn ("Could not get the system bus. Make sure "
                 "the message bus daemon is running!");
    else
        mm_warn ("Could not acquire the '%s' service name", name);

    if (manager)
        g_object_set (manager, MM_BASE_MANAGER_CONNECTION, NULL, NULL);

    g_main_loop_quit (loop);
}
예제 #9
0
static void
connection_enabled (MMAtSerialPort *port,
                    GMatchInfo *match_info,
                    gpointer user_data)
{
    MMModemIcera *self = MM_MODEM_ICERA (user_data);
    MMAtSerialPort *primary;
    char *str;
    int status, cid, tmp;

    cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self));
    if (cid < 0)
        return;

    str = g_match_info_fetch (match_info, 1);
    g_return_if_fail (str != NULL);
    tmp = atoi (str);
    g_free (str);

    /* Make sure the unsolicited message's CID matches the current CID */
    if (tmp != cid)
        return;

    str = g_match_info_fetch (match_info, 2);
    g_return_if_fail (str != NULL);
    status = atoi (str);
    g_free (str);

    switch (status) {
    case 0:
        /* Disconnected */
        if (mm_modem_get_state (MM_MODEM (self)) >= MM_MODEM_STATE_CONNECTED)
            mm_modem_disconnect (MM_MODEM (self), icera_disconnect_done, NULL);
        break;
    case 1:
        /* Connected */
        connect_pending_done (self);
        break;
    case 2:
        /* Connecting */
        break;
    case 3:
        /* Call setup failure? */
        primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM(self), MM_AT_PORT_FLAG_PRIMARY);
        g_assert (primary);
        /* Get additional error details */
        mm_at_serial_port_queue_command (primary, "AT%IER?", 3,
                                         query_network_error_code_done, self);
        break;
    default:
        mm_warn ("Unknown Icera connect status %d", status);
        break;
    }
}
예제 #10
0
static void
find_device_support_ready (MMPluginManager *plugin_manager,
                           GAsyncResult *result,
                           FindDeviceSupportContext *ctx)
{
    GError *error = NULL;

    if (!mm_plugin_manager_find_device_support_finish (plugin_manager, result, &error)) {
        mm_warn ("Couldn't find support for device at '%s': %s",
                 mm_device_get_path (ctx->device),
                 error->message);
        g_error_free (error);
    } else if (!mm_device_create_modem (ctx->device, ctx->self->priv->object_manager, &error)) {
        mm_warn ("Couldn't create modem for device at '%s': %s",
                 mm_device_get_path (ctx->device),
                 error->message);
        g_error_free (error);
    } else {
        mm_info ("Modem for device at '%s' successfully created",
                 mm_device_get_path (ctx->device));
    }

    find_device_support_context_free (ctx);
}
예제 #11
0
static void
get_local_timestamp_done (MMAtSerialPort *port,
                          GString *response,
                          GError *error,
                          gpointer user_data)
{
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
    MMModemIceraTimestamp *timestamp;
    char sign;
    int offset;

    /* If the modem has already been removed, return without
     * scheduling callback */
    if (mm_callback_info_check_modem_removed (info))
        return;

    if (error) {
        info->error = g_error_copy (error);
        goto out;
    }

    timestamp = g_malloc0 (sizeof (MMModemIceraTimestamp));

    if (g_str_has_prefix (response->str, "*TLTS: ") &&
        sscanf (response->str + 7,
                "\"%02d/%02d/%02d,%02d:%02d:%02d%c%02d\"",
                &timestamp->year,
                &timestamp->month,
                &timestamp->day,
                &timestamp->hour,
                &timestamp->minute,
                &timestamp->second,
                &sign, &offset) == 8) {
        if (sign == '-')
            timestamp->tz_offset = -offset;
        else
            timestamp->tz_offset = offset;
        mm_callback_info_set_result (info, timestamp, g_free);
    } else {
        mm_warn ("Unknown *TLTS response: %s", response->str);
        mm_callback_info_set_result (info, NULL, g_free);
        g_free (timestamp);
    }

 out:
    mm_callback_info_schedule (info);
}
예제 #12
0
static void
grab_port (MMManager *manager,
           MMPlugin *plugin,
           GUdevDevice *device,
           GUdevDevice *physical_device)
{
    GError *error = NULL;
    MMBaseModem *modem;
    MMBaseModem *existing;

    existing = g_hash_table_lookup (manager->priv->modems,
                                    g_udev_device_get_sysfs_path (physical_device));

    /* While grabbing the first port, modem will get created */
    modem = mm_plugin_grab_port (plugin,
                                 g_udev_device_get_subsystem (device),
                                 g_udev_device_get_name (device),
                                 existing,
                                 &error);
    if (!modem) {
        mm_warn ("plugin '%s' claimed to support %s/%s but couldn't: (%d) %s",
                 mm_plugin_get_name (plugin),
                 g_udev_device_get_subsystem (device),
                 g_udev_device_get_name (device),
                 error ? error->code : -1,
                 (error && error->message) ? error->message : "(unknown)");
        g_clear_error (&error);

        if (existing)
            check_export_modem (manager, existing);
        return;
    }

    mm_info ("(%s): modem %s claimed port %s",
             mm_plugin_get_name (plugin),
             mm_base_modem_get_device (modem),
             g_udev_device_get_name (device));

    if (existing) {
        g_assert (existing == modem);
        check_export_modem (manager, modem);
    } else {
        /* If the modem was just created, store it */
        add_modem (manager, modem, plugin);
    }
}
static void
mm_auth_provider_polkit_init (MMAuthProviderPolkit *self)
{
    GError *error = NULL;

    self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
                                              MM_TYPE_AUTH_PROVIDER_POLKIT,
                                              MMAuthProviderPolkitPrivate);

    self->priv->authority = polkit_authority_get_sync (NULL, &error);
    if (!self->priv->authority) {
        /* NOTE: we failed to create the polkit authority, but we still create
         * our AuthProvider. Every request will fail, though. */
        mm_warn ("failed to create PolicyKit authority: '%s'",
                 error ? error->message : "unknown");
		g_clear_error (&error);
    }
}
static void
modem_power_up (MMIfaceModem *self,
                GAsyncReadyCallback callback,
                gpointer user_data)
{
    mm_warn ("Not in full functionality status, power-up command is needed. "
             "Note that it may reboot the modem.");

    /* Try to go to full functionality mode without rebooting the system.
     * Works well if we previously switched off the power with CFUN=4
     */
    mm_base_modem_at_command (MM_BASE_MODEM (self),
                              "+CFUN=1,0",
                              3,
                              FALSE,
                              callback,
                              user_data);
}
예제 #15
0
static void
serial_port_timed_out_cb (MMSerialPort *port,
                          guint n_consecutive_timeouts,
                          gpointer user_data)
{
    MMBaseModem *self = (MM_BASE_MODEM (user_data));

    if (self->priv->max_timeouts > 0 &&
        n_consecutive_timeouts >= self->priv->max_timeouts) {
        mm_warn ("(%s/%s) port timed out %u times, marking modem '%s' as disabled",
                 mm_port_type_get_string (mm_port_get_port_type (MM_PORT (port))),
                 mm_port_get_device (MM_PORT (port)),
                 n_consecutive_timeouts,
                 g_dbus_object_get_object_path (G_DBUS_OBJECT (self)));

        /* Only set action to invalidate modem if not already done */
        g_cancellable_cancel (self->priv->cancellable);
    }
}
예제 #16
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);
}
static void
connect_3gpp_qmistatus_ready (MMBaseModem *modem,
                              GAsyncResult *res,
                              DetailedConnectContext *ctx)
{
    const gchar *result;
    GError *error = NULL;

    result = mm_base_modem_at_command_finish (MM_BASE_MODEM (ctx->modem),
                                              res,
                                              &error);
    if (!result) {
        mm_warn ("QMI connection status failed: %s", error->message);
        g_simple_async_result_take_error (ctx->result, error);
        detailed_connect_context_complete_and_free (ctx);
        return;
    }

    result = mm_strip_tag (result, "$NWQMISTATUS:");
    if (g_strrstr(result, "QMI State: CONNECTED")) {
        mm_dbg("Connected");
        detailed_connect_context_complete_and_free_successful (ctx);
        return;
    } else {
        mm_dbg("Error: '%s'", result);
        if (ctx->retries > 0) {
            ctx->retries--;
            mm_dbg("Retrying status check in a second. %d retries left.",
                   ctx->retries);
            g_timeout_add_seconds(1, (GSourceFunc)connect_3gpp_qmistatus, ctx);
            return;
        }
        g_simple_async_result_set_error (ctx->result,
                                         MM_CORE_ERROR,
                                         MM_CORE_ERROR_FAILED,
                                         "%s", result);
    }
    detailed_connect_context_complete_and_free (ctx);
}
예제 #18
0
static void
bus_acquired_cb (GDBusConnection *connection,
                 const gchar *name,
                 gpointer user_data)
{
    GError *error = NULL;

    mm_dbg ("Bus acquired, creating manager...");

    /* Create Manager object */
    g_assert (!manager);
    manager = mm_base_manager_new (connection,
                                   mm_context_get_test_plugin_dir (),
                                   !mm_context_get_test_no_auto_scan (),
                                   mm_context_get_test_enable (),
                                   &error);
    if (!manager) {
        mm_warn ("Could not create manager: %s", error->message);
        g_error_free (error);
        g_main_loop_quit (loop);
        return;
    }
}
예제 #19
0
static void
supports_port_ready_cb (MMPlugin *plugin,
                        GAsyncResult *result,
                        SupportsInfo *info)
{
    MMPluginSupportsResult support_result;
    GError *error = NULL;

    /* Get supports check results */
    support_result = mm_plugin_supports_port_finish (plugin,
                                                     result,
                                                     &error);
    if (error) {
        mm_warn ("(%s): (%s) error when checking support: '%s'",
                 mm_plugin_get_name (plugin),
                 info->name,
                 error->message);
        g_error_free (error);
    }

    switch (support_result) {
    case MM_PLUGIN_SUPPORTS_PORT_SUPPORTED:
        /* Found a best plugin */
        info->best_plugin = plugin;

        if (info->suggested_plugin &&
            info->suggested_plugin != plugin) {
            /* The last plugin we tried said it supported this port, but it
             * doesn't correspond with the one we're being suggested. */
            g_warn_if_reached ();
        }

        mm_dbg ("(%s): (%s) found best plugin for port",
                mm_plugin_get_name (info->best_plugin),
                info->name);
        info->current = NULL;

        /* Schedule checking support, which will end the operation */
        info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle,
                                      info);
        break;

    case MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED:
        if (info->suggested_plugin) {
            if (info->suggested_plugin == plugin) {
                /* If the plugin that just completed the support check claims
                 * not to support this port, but this plugin is clearly the
                 * right plugin since it claimed this port's physical modem,
                 * just drop the port.
                 */
                mm_dbg ("(%s/%s): ignoring port unsupported by physical modem's plugin",
                        info->subsys,
                        info->name);
                info->best_plugin = NULL;
                info->current = NULL;
            } else {
                /* The last plugin we tried is NOT the one we got suggested, so
                 * directly check support with the suggested plugin. If we
                 * already checked its support, it won't be checked again. */
                info->current = g_slist_find (info->current,
                                              info->suggested_plugin);
            }
        } else {
            /* If the plugin knows it doesn't support the modem, just keep on
             * checking the next plugin.
             */
            info->current = g_slist_next (info->current);
        }
        info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle,
                                      info);
        break;

    case MM_PLUGIN_SUPPORTS_PORT_DEFER:
        /* Try with the suggested one after being deferred */
        if (info->suggested_plugin) {
            mm_dbg ("(%s): (%s) deferring support check, suggested: %s",
                    mm_plugin_get_name (MM_PLUGIN (info->current->data)),
                    info->name,
                    mm_plugin_get_name (MM_PLUGIN (info->suggested_plugin)));
            info->current = g_slist_find (info->current,
                                          info->suggested_plugin);
        } else {
            mm_dbg ("(%s): (%s) deferring support check",
                    mm_plugin_get_name (MM_PLUGIN (info->current->data)),
                    info->name);
        }
        /* Schedule checking support */
        info->source_id = g_timeout_add_seconds (SUPPORTS_DEFER_TIMEOUT_SECS,
                                                 (GSourceFunc)find_port_support_idle,
                                                 info);
        break;

    case MM_PLUGIN_SUPPORTS_PORT_DEFER_UNTIL_SUGGESTED:
        /* If we arrived here and we already have a plugin suggested, use it */
        if (info->suggested_plugin) {
            mm_dbg ("(%s): (%s) task completed, got suggested plugin",
                    mm_plugin_get_name (info->suggested_plugin),
                    info->name);
            /* Schedule checking support, which will end the operation */
            info->best_plugin = info->suggested_plugin;
            info->current = NULL;
            info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle,
                                          info);
        } else {
            /* We are deferred until a suggested plugin is given. If last supports task
             * of a given device is finished without finding a best plugin, this task
             * will get finished reporting unsupported. */
            mm_dbg ("(%s) deferring support check until result suggested",
                    info->name);
            info->defer_until_suggested = TRUE;
        }
        break;
    }
}
예제 #20
0
int
main (int argc, char *argv[])
{
    GMainLoop *inner;
    GError *err = NULL;
    guint name_id;

    g_type_init ();

    /* Setup application context */
    mm_context_init (argc, argv);

    if (!mm_log_setup (mm_context_get_log_level (),
                       mm_context_get_log_file (),
                       mm_context_get_timestamps (),
                       mm_context_get_relative_timestamps (),
                       mm_context_get_debug (),
                       &err)) {
        g_warning ("Failed to set up logging: %s", err->message);
        g_error_free (err);
        exit (1);
    }

    g_unix_signal_add (SIGTERM, quit_cb, NULL);
    g_unix_signal_add (SIGINT, quit_cb, NULL);

    mm_info ("ModemManager (version " MM_DIST_VERSION ") starting in %s bus...",
             mm_context_get_test_session () ? "session" : "system");

    /* Acquire name, don't allow replacement */
    name_id = g_bus_own_name (mm_context_get_test_session () ? G_BUS_TYPE_SESSION : G_BUS_TYPE_SYSTEM,
                              MM_DBUS_SERVICE,
                              G_BUS_NAME_OWNER_FLAGS_NONE,
                              bus_acquired_cb,
                              name_acquired_cb,
                              name_lost_cb,
                              NULL,
                              NULL);

    /* Go into the main loop */
    loop = g_main_loop_new (NULL, FALSE);
    g_main_loop_run (loop);

    /* Clear the global variable, so that subsequent requests to
     * exit succeed. */
    inner = loop;
    loop = NULL;

    if (manager) {
        GTimer *timer;

        mm_base_manager_shutdown (manager);

        /* Wait for all modems to be disabled and removed, but don't wait
         * forever: if disabling the modems takes longer than 20s, just
         * shutdown anyway. */
        timer = g_timer_new ();
        while (mm_base_manager_num_modems (manager) &&
               g_timer_elapsed (timer, NULL) < (gdouble)MAX_SHUTDOWN_TIME_SECS) {
            GMainContext *ctx = g_main_loop_get_context (inner);

            g_main_context_iteration (ctx, FALSE);
            g_usleep (50);
        }

        if (mm_base_manager_num_modems (manager))
            mm_warn ("Disabling modems took too long, "
                     "shutting down with '%u' modems around",
                     mm_base_manager_num_modems (manager));

        g_object_unref (manager);
        g_timer_destroy (timer);
    }

    g_main_loop_unref (inner);

    g_bus_unown_name (name_id);

    mm_info ("ModemManager is shut down");

    mm_log_shutdown ();

    return 0;
}
예제 #21
0
void
mm_base_modem_release_port (MMBaseModem *self,
                            const gchar *subsys,
                            const gchar *name)
{
    gchar *key;
    MMPort *port;
    GList *l;

    g_return_if_fail (MM_IS_BASE_MODEM (self));
    g_return_if_fail (name != NULL);
    g_return_if_fail (subsys != NULL);

    if (!g_str_equal (subsys, "tty") &&
        !g_str_equal (subsys, "net"))
        return;

    key = get_hash_key (subsys, name);

    /* Find the port */
    port = g_hash_table_lookup (self->priv->ports, key);
    if (!port) {
        mm_warn ("(%s/%s): cannot release port, not found",
                 subsys, name);
        g_free (key);
        return;
    }

    if (port == (MMPort *)self->priv->primary) {
        /* Cancel modem-wide cancellable; no further actions can be done
         * without a primary port. */
        g_cancellable_cancel (self->priv->cancellable);

        g_clear_object (&self->priv->primary);
    }

    l = g_list_find (self->priv->data, port);
    if (l) {
        g_object_unref (l->data);
        self->priv->data = g_list_delete_link (self->priv->data, l);
    }

    if (port == (MMPort *)self->priv->secondary)
        g_clear_object (&self->priv->secondary);

    if (port == (MMPort *)self->priv->qcdm)
        g_clear_object (&self->priv->qcdm);

    if (port == (MMPort *)self->priv->gps_control)
        g_clear_object (&self->priv->gps_control);

    if (port == (MMPort *)self->priv->gps)
        g_clear_object (&self->priv->gps);

#if defined WITH_QMI
    l = g_list_find (self->priv->qmi, port);
    if (l) {
        g_object_unref (l->data);
        self->priv->qmi = g_list_delete_link (self->priv->qmi, l);
    }
#endif

    /* Remove it from the tracking HT */
    mm_dbg ("(%s/%s) type %s released from %s",
            subsys,
            name,
            mm_port_type_get_string (mm_port_get_port_type (port)),
            mm_port_get_device (port));
    g_hash_table_remove (self->priv->ports, key);
    g_free (key);
}
예제 #22
0
MMQmiPort *
mm_base_modem_peek_port_qmi_for_data (MMBaseModem *self,
                                      MMPort *data,
                                      GError **error)
{
    MMQmiPort *found;
    GUdevClient *client;
    GUdevDevice *data_device;
    GUdevDevice *data_device_parent;
    GList *l;

    if (mm_port_get_subsys (data) != MM_PORT_SUBSYS_NET) {
        g_set_error (error,
                     MM_CORE_ERROR,
                     MM_CORE_ERROR_UNSUPPORTED,
                     "Cannot look for QMI port associated to a non-net data port");
        return NULL;
    }

    /* don't listen for uevents */
    client = g_udev_client_new (NULL);

    /* Get udev device for the data port */
    data_device = (g_udev_client_query_by_subsystem_and_name (
                       client,
                       "net",
                       mm_port_get_device (data)));
    if (!data_device) {
        g_set_error (error,
                     MM_CORE_ERROR,
                     MM_CORE_ERROR_FAILED,
                     "Couldn't find udev device for port 'net/%s'",
                     mm_port_get_device (data));
        g_object_unref (client);
        return NULL;
    }

    /* Get parent of the data device */
    data_device_parent = g_udev_device_get_parent (data_device);
    if (!data_device_parent) {
        g_set_error (error,
                     MM_CORE_ERROR,
                     MM_CORE_ERROR_FAILED,
                     "Couldn't get udev device parent for port 'net/%s'",
                     mm_port_get_device (data));
        g_object_unref (data_device);
        g_object_unref (client);
        return NULL;
    }

    /* Now walk the list of QMI ports looking for a match */
    found = NULL;
    for (l = self->priv->qmi; l && !found; l = g_list_next (l)) {
        GUdevDevice *qmi_device;
        GUdevDevice *qmi_device_parent;

        /* Get udev device for the QMI port */
        qmi_device = (g_udev_client_query_by_subsystem_and_name (
                          client,
                          "usb",
                          mm_port_get_device (MM_PORT (l->data))));
        if (!qmi_device) {
            qmi_device = (g_udev_client_query_by_subsystem_and_name (
                              client,
                              "usbmisc",
                              mm_port_get_device (MM_PORT (l->data))));
            if (!qmi_device) {
                mm_warn ("Couldn't get udev device for QMI port '%s'",
                         mm_port_get_device (MM_PORT (l->data)));
                continue;
            }
        }

        /* Get parent of the QMI device */
        qmi_device_parent = g_udev_device_get_parent (qmi_device);
        g_object_unref (qmi_device);

        if (!data_device_parent) {
            mm_warn ("Couldn't get udev device parent for QMI port '%s'",
                     mm_port_get_device (MM_PORT (l->data)));
            continue;
        }

        if (g_str_equal (g_udev_device_get_sysfs_path (data_device_parent),
                         g_udev_device_get_sysfs_path (qmi_device_parent)))
            found = MM_QMI_PORT (l->data);

        g_object_unref (qmi_device_parent);
    }

    g_object_unref (data_device_parent);
    g_object_unref (data_device);
    g_object_unref (client);

    if (!found) {
        /* For the case where we have only 1 data port and 1 QMI port and they
         * don't match with the previous rules (e.g. in some Huawei modems),
         * just return the found one */
        if (g_list_length (self->priv->data) == 1 &&
            g_list_length (self->priv->qmi) == 1 &&
            self->priv->data->data == data) {
            mm_info ("Assuming QMI port '%s' is associated to net/%s",
                     mm_port_get_device (MM_PORT (self->priv->qmi->data)),
                     mm_port_get_device (data));
            found = MM_QMI_PORT (self->priv->qmi->data);
        } else {
            g_set_error (error,
                         MM_CORE_ERROR,
                         MM_CORE_ERROR_NOT_FOUND,
                         "Couldn't find associated QMI port for 'net/%s'",
                         mm_port_get_device (data));
            return NULL;
        }
    }

    return found;
}
예제 #23
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);
}
예제 #24
0
static void
sysinfo_done (MMAtSerialPort *port,
              GString *response,
              GError *error,
              gpointer user_data)
{
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
    GRegex *r;
    GMatchInfo *match_info;
    const char *reply;

    /* If the modem has already been removed, return without
     * scheduling callback */
    if (mm_callback_info_check_modem_removed (info))
        return;

    if (error) {
        /* Leave superclass' reg state alone if AT^SYSINFO isn't supported */
        goto done;
    }

    reply = strip_response (response->str, "^SYSINFO:");

    /* Format is "<srv_status>,<srv_domain>,<roam_status>,<sys_mode>,<sim_state>" */
    r = g_regex_new ("\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)",
                     G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
    if (!r) {
        mm_warn ("Huawei: ^SYSINFO parse regex creation failed.");
        goto done;
    }

    g_regex_match (r, reply, 0, &match_info);
    if (g_match_info_get_match_count (match_info) >= 5) {
        MMModemCdmaRegistrationState reg_state;
        guint32 val = 0;

        /* At this point the generic code already knows we've been registered */
        reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;

        if (uint_from_match_item (match_info, 1, &val)) {
            if (val == 2) {
                /* Service available, check roaming state */
                val = 0;
                if (uint_from_match_item (match_info, 3, &val)) {
                    if (val == 0)
                        reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_HOME;
                    else if (val == 1)
                        reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING;
                }
            }
        }

        /* Check service type */
        val = 0;
        if (uint_from_match_item (match_info, 4, &val)) {
            if (val == 2)
                mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state);
            else if (val == 4)
                mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, reg_state);
            else if (val == 8) {
                mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state);
                mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, reg_state);
            }
        } else {
            /* Say we're registered to something even though sysmode parsing failed */
            mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state);
        }
    } else
        mm_warn ("Huawei: failed to parse ^SYSINFO response.");

    g_match_info_free (match_info);
    g_regex_unref (r);

done:
    mm_callback_info_schedule (info);
}
예제 #25
0
MMBaseModem *
mm_plugin_create_modem (MMPlugin  *self,
                        MMDevice *device,
                        GError   **error)
{
    MMBaseModem *modem = NULL;
    GList *port_probes, *l;

    port_probes = mm_device_peek_port_probe_list (device);

    /* Let the plugin create the modem from the port probe results */
    modem = MM_PLUGIN_GET_CLASS (self)->create_modem (MM_PLUGIN (self),
                                                      mm_device_get_path (device),
                                                      mm_device_get_drivers (device),
                                                      mm_device_get_vendor (device),
                                                      mm_device_get_product (device),
                                                      port_probes,
                                                      error);
    if (modem) {
        /* Grab each port */
        for (l = port_probes; l; l = g_list_next (l)) {
            GError *inner_error = NULL;
            MMPortProbe *probe = MM_PORT_PROBE (l->data);
            gboolean grabbed;

            /* If grabbing a port fails, just warn. We'll decide if the modem is
             * valid or not when all ports get organized */

            /* We apply again the subsystem filter, as the port may have been
             * probed and accepted by the generic plugin, which is overwritten
             * by the specific one when needed. */
            if (apply_subsystem_filter (self, mm_port_probe_peek_port (probe))) {
                grabbed = FALSE;
                inner_error = g_error_new (MM_CORE_ERROR,
                                           MM_CORE_ERROR_UNSUPPORTED,
                                           "unsupported subsystem: '%s'",
                                           mm_port_probe_get_port_subsys (probe));
            }
#if !defined WITH_QMI
            else if (mm_port_probe_get_port_type (probe) == MM_PORT_TYPE_NET &&
                     g_str_equal (mm_device_utils_get_port_driver (mm_port_probe_peek_port (probe)),
                                  "qmi_wwan")) {
                grabbed = FALSE;
                inner_error = g_error_new (MM_CORE_ERROR,
                                           MM_CORE_ERROR_UNSUPPORTED,
                                           "ignoring QMI net port");
            }
#endif
            else if (MM_PLUGIN_GET_CLASS (self)->grab_port)
                grabbed = MM_PLUGIN_GET_CLASS (self)->grab_port (MM_PLUGIN (self),
                                                                 modem,
                                                                 probe,
                                                                 &inner_error);
            else
                grabbed = mm_base_modem_grab_port (modem,
                                                   mm_port_probe_get_port_subsys (probe),
                                                   mm_port_probe_get_port_name (probe),
                                                   mm_port_probe_get_port_type (probe),
                                                   MM_AT_PORT_FLAG_NONE,
                                                   &inner_error);
            if (!grabbed) {
                mm_warn ("Could not grab port (%s/%s): '%s'",
                         mm_port_probe_get_port_subsys (MM_PORT_PROBE (l->data)),
                         mm_port_probe_get_port_name (MM_PORT_PROBE (l->data)),
                         inner_error ? inner_error->message : "unknown error");
                g_clear_error (&inner_error);
            }
        }

        /* If organizing ports fails, consider the modem invalid */
        if (!mm_base_modem_organize_ports (modem, error))
            g_clear_object (&modem);
    }

    return modem;
}