Beispiel #1
0
static void
remove_modem (MMManager *manager,
              MMBaseModem *modem)
{
    gchar *path;
    gchar *device;

    device = g_strdup (mm_base_modem_get_device (modem));
    path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (modem)));

    /* If we get DBus object path, modem was exported */
    if (path) {
        g_dbus_object_manager_server_unexport (manager->priv->object_manager, path);
        g_object_set (modem,
                      MM_BASE_MODEM_CONNECTION, NULL,
                      NULL);

        mm_dbg ("Unexported modem '%s' from path '%s'", device, path);
        g_free (path);
    } else {
        mm_dbg ("Removing modem '%s', which wasn't exported yet", device);
    }

    /* Run dispose before unref-ing, in order to cleanup the SIM object,
     * if any (which also holds a reference to the modem object) */
    g_object_run_dispose (G_OBJECT (modem));
    g_hash_table_remove (manager->priv->modems, device);
    g_free (device);
}
Beispiel #2
0
static void
device_removed (MMManager *manager,
                GUdevDevice *device)
{
    MMBaseModem *modem;
    const char *subsys, *name;

    g_return_if_fail (device != NULL);

    subsys = g_udev_device_get_subsystem (device);
    name = g_udev_device_get_name (device);

    /* Ensure cached port probe infos get removed when the port is gone */
    mm_port_probe_cache_remove (device);

    if (strcmp (subsys, "usb") != 0) {
        /* find_modem_for_port handles tty and net removal */
        modem = find_modem_for_port (manager, subsys, name);
        if (modem) {
            mm_info ("(%s/%s): released by modem %s",
                     subsys,
                     name,
                     mm_base_modem_get_device (modem));
            mm_base_modem_release_port (modem, subsys, name);
            return;
        }
    } else {
        /* This case is designed to handle the case where, at least with kernel 2.6.31, unplugging
         * an in-use ttyACMx device results in udev generating remove events for the usb, but the
         * ttyACMx device (subsystem tty) is not removed, since it was in-use.  So if we have not
         * found a modem for the port (above), we're going to look here to see if we have a modem
         * associated with the newly removed device.  If so, we'll remove the modem, since the
         * device has been removed.  That way, if the device is reinserted later, we'll go through
         * the process of exporting it.
         */
        const char *sysfs_path = g_udev_device_get_sysfs_path (device);

        modem = find_modem_for_device (manager, sysfs_path);
        if (modem) {
            mm_dbg ("Removing modem claimed by removed device %s", sysfs_path);
            remove_modem (manager, modem);
            return;
        }
    }

    /* Maybe a plugin is checking whether or not the port is supported.
     * TODO: Cancel every possible supports check in this port. */
}
Beispiel #3
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);
    }
}
Beispiel #4
0
static MMBaseModem *
find_modem_for_device (MMManager *manager,
                       const gchar *device)
{
    GHashTableIter iter;
    gpointer key, value;

    g_hash_table_iter_init (&iter, manager->priv->modems);
    while (g_hash_table_iter_next (&iter, &key, &value)) {
        MMBaseModem *candidate = MM_BASE_MODEM (value);

        if (g_str_equal (device,
                         mm_base_modem_get_device (candidate)))
            return candidate;
    }

    return NULL;
}
Beispiel #5
0
static void
add_modem (MMManager *manager,
           MMBaseModem *modem,
           MMPlugin *plugin)
{
    const gchar *device;

    device = mm_base_modem_get_device (modem);
    if (!g_hash_table_lookup (manager->priv->modems, device)) {
        mm_dbg ("Added modem %s", device);
        g_hash_table_insert (manager->priv->modems,
                             g_strdup (device),
                             modem);
        g_object_set_data (G_OBJECT (modem), MANAGER_PLUGIN_TAG, plugin);
        g_signal_connect (modem, "notify::" MM_BASE_MODEM_VALID, G_CALLBACK (modem_valid), manager);
    }

    check_export_modem (manager, modem);
}
Beispiel #6
0
static void
debug_modem_info (MMManager *self,
                  MMBaseModem *modem,
                  const gchar *path)
{
    GUdevDevice *physdev;
    const gchar *subsys;

    physdev = g_udev_client_query_by_sysfs_path (self->priv->udev,
                                                 mm_base_modem_get_device (modem));
    subsys = (physdev ?
              g_udev_device_get_subsystem (physdev) :
              NULL);

    mm_dbg ("(%s): '%s' modem, VID 0x%04X PID 0x%04X (%s)",
            path,
            mm_base_modem_get_plugin (modem),
            (mm_base_modem_get_vendor_id (modem) & 0xFFFF),
            (mm_base_modem_get_product_id (modem) & 0xFFFF),
            subsys ? subsys : "unknown");

    if (physdev)
        g_object_unref (physdev);
}
Beispiel #7
0
gboolean
mm_base_modem_grab_port (MMBaseModem *self,
                         const gchar *subsys,
                         const gchar *name,
                         MMPortType ptype,
                         MMAtPortFlag at_pflags,
                         GError **error)
{
    MMPort *port;
    gchar *key;

    g_return_val_if_fail (MM_IS_BASE_MODEM (self), FALSE);
    g_return_val_if_fail (subsys != NULL, FALSE);
    g_return_val_if_fail (name != NULL, FALSE);

    /* Only allow 'tty', 'net' and 'cdc-wdm' ports */
    if (!g_str_equal (subsys, "net") &&
        !g_str_equal (subsys, "tty") &&
        !(g_str_has_prefix (subsys, "usb") && g_str_has_prefix (name, "cdc-wdm"))) {
        g_set_error (error,
                     MM_CORE_ERROR,
                     MM_CORE_ERROR_UNSUPPORTED,
                     "Cannot add port '%s/%s', unhandled subsystem",
                     subsys,
                     name);
        return FALSE;
    }

    /* Check whether we already have it stored */
    key = get_hash_key (subsys, name);
    port = g_hash_table_lookup (self->priv->ports, key);
    if (port) {
        g_set_error (error,
                     MM_CORE_ERROR,
                     MM_CORE_ERROR_UNSUPPORTED,
                     "Cannot add port '%s/%s', already exists",
                     subsys,
                     name);
        g_free (key);
        return FALSE;
    }

    /* Serial ports... */
    if (g_str_equal (subsys, "tty")) {
        if (ptype == MM_PORT_TYPE_QCDM)
            /* QCDM port */
            port = MM_PORT (mm_qcdm_serial_port_new (name));
        else if (ptype == MM_PORT_TYPE_AT) {
            /* AT port */
            port = MM_PORT (mm_at_serial_port_new (name));

            /* Set common response parser */
            mm_at_serial_port_set_response_parser (MM_AT_SERIAL_PORT (port),
                                                   mm_serial_parser_v1_parse,
                                                   mm_serial_parser_v1_new (),
                                                   mm_serial_parser_v1_destroy);
            /* Store flags already */
            mm_at_serial_port_set_flags (MM_AT_SERIAL_PORT (port), at_pflags);
        } else if (ptype == MM_PORT_TYPE_GPS) {
            /* Raw GPS port */
            port = MM_PORT (mm_gps_serial_port_new (name));
        } else {
            g_set_error (error,
                         MM_CORE_ERROR,
                         MM_CORE_ERROR_UNSUPPORTED,
                         "Cannot add port '%s/%s', unhandled serial type",
                         subsys,
                         name);
            g_free (key);
            return FALSE;
        }

        /* For serial ports, enable port timeout checks */
        g_signal_connect (port,
                          "timed-out",
                          G_CALLBACK (serial_port_timed_out_cb),
                          self);
    }
    /* Net ports... */
    else if (g_str_equal (subsys, "net")) {
        port = MM_PORT (g_object_new (MM_TYPE_PORT,
                                      MM_PORT_DEVICE, name,
                                      MM_PORT_SUBSYS, MM_PORT_SUBSYS_NET,
                                      MM_PORT_TYPE, MM_PORT_TYPE_NET,
                                      NULL));
    }
    /* QMI ports... */
    else if (g_str_has_prefix (subsys, "usb") &&
             g_str_has_prefix (name, "cdc-wdm")) {
#if defined WITH_QMI
        port = MM_PORT (mm_qmi_port_new (name));
#else
        g_set_error (error,
                     MM_CORE_ERROR,
                     MM_CORE_ERROR_UNSUPPORTED,
                     "Cannot add port '%s/%s', QMI support not available",
                     subsys,
                     name);
        g_free (key);
        return FALSE;
#endif
    }
    else
        /* We already filter out before all non-tty, non-net, non-qmi ports */
        g_assert_not_reached();

    mm_dbg ("(%s) type '%s' claimed by %s",
            name,
            mm_port_type_get_string (ptype),
            mm_base_modem_get_device (self));

    /* Add it to the tracking HT.
     * Note: 'key' and 'port' now owned by the HT. */
    g_hash_table_insert (self->priv->ports, key, port);

    return TRUE;
}
Beispiel #8
0
static void
check_export_modem (MMManager *self,
                    MMBaseModem *modem)
{
    GError *error = NULL;
    static guint32 id = 0;
    const gchar *modem_physdev;
    const gchar *name;
    const gchar *subsys;
    gchar *path;

    /* A modem is only exported to D-Bus when both of the following are true:
     *
     *   1) the modem is valid
     *   2) all ports the modem provides have either been grabbed or are
     *       unsupported by any plugin
     *
     * This ensures that all the modem's ports are completely ready before
     * any clients can do anything with it.
     *
     * FIXME: if udev or the kernel are really slow giving us ports, there's a
     * chance that a port could show up after the modem is already created and
     * all other ports are already handled.  That chance is very small though.
     */

    modem_physdev = mm_base_modem_get_device (modem);
    g_assert (modem_physdev);

    /* Check for ports that are in the process of being interrogated by plugins */
    if (mm_plugin_manager_is_finding_device_support (self->priv->plugin_manager,
                                                     modem_physdev,
                                                     &subsys,
                                                     &name)) {
        mm_dbg ("(%s/%s): outstanding support task prevents export of '%s'",
                subsys, name, modem_physdev);
        return;
    }

    /* Plugin manager is not trying to find more ports supported by this device,
     * so we can organize the ports now (if not done already). */
    if (!mm_base_modem_organize_ports (modem, &error)) {
        /* If the ports were not properly organized, the modem will be marked as
         * invalid and therefore removed */
        mm_err ("Failed to organize modem ports: '%s'",
                error->message);
        g_error_free (error);
        remove_modem (self, modem);
        return;
    }

    /* If modem not yet valid (not fully initialized), don't export it */
    if (!mm_base_modem_get_valid (modem))
        return;

    /* Don't export already exported modems */
    g_object_get (modem,
                  "g-object-path", &path,
                  NULL);
    if (path) {
        g_free (path);
        mm_dbg ("Modem '%s' already exported", modem_physdev);
        return;
    }

    /* No outstanding port tasks, so if the modem is valid we can export it */
    path = g_strdup_printf (MM_DBUS_MODEM_PREFIX "/%d", id++);
    g_object_set (modem,
                  "g-object-path", path,
                  MM_BASE_MODEM_CONNECTION, self->priv->connection,
                  NULL);
    g_dbus_object_manager_server_export (self->priv->object_manager,
                                         G_DBUS_OBJECT_SKELETON (modem));
    mm_dbg ("Exported modem '%s' at path '%s'", modem_physdev, path);

    /* Once connected, dump additional debug info about the modem */
    debug_modem_info (self, modem, path);
    g_free (path);
}