diff options
author | Dan Williams <dcbw@redhat.com> | 2012-02-01 01:43:54 -0600 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2012-02-28 10:06:04 -0600 |
commit | 4dad94d5004f325e25dc3b09d87585eab38d4c3f (patch) | |
tree | 38a5bb148952c333e18bfbd959e27573ab3364d9 /src/mm-manager.c | |
parent | 36ee1b9c76a681b44516852372944b82c7616892 (diff) |
core: rework port grabbing and organization
Make port roles more flexible. We have modems that do PPP
on interfaces other than the primary interface, and that
wasn't possible with the old code. So clean up all that
logic and move the port organization code into the core
so we can reduce code in the plugins.
In the new world order, the plugins say whether the port
is a QCDM port, an AT port, or ignored. If it's an AT
port the plugins get to tag it as primary, secondary, or
PPP, or any combination of the 3. This allows for modems
where PPP should really be done on the secondary port
(Huawei E220, Sierra devices) so that the primary port
stays open for command and status.
Modem subclasses no longer get asked to handle port grabbing
themselves. Instead, that's now done by the generic classes
(MMGenericCdma and MMGenericGsm) and the plugins are notified
when a port is grabbed so they can add unsolicited response
handlers for it. After all ports are grabbed by the generic
classes, they get "organized", which assigns various ports
to the roles of PRIMARY, SECONDARY, DATA, and QCDM based
on specific rules and hints that the plugin provided (which
are expressed as MMAtPortFlags). The plugins then have
a chance to perform fixups on the primary port if they choose.
The plugin code is responsible for determining the port
hints (ie MMAtPortFlags) at probe time, instead of having
a combination of the plugin and the modem class do the
job. This simplifies things greatly for the plugins at
the expense of more complicated logic in the core.
Diffstat (limited to 'src/mm-manager.c')
-rw-r--r-- | src/mm-manager.c | 143 |
1 files changed, 85 insertions, 58 deletions
diff --git a/src/mm-manager.c b/src/mm-manager.c index 6767353e..5f114bba 100644 --- a/src/mm-manager.c +++ b/src/mm-manager.c @@ -247,13 +247,36 @@ remove_modem (MMManager *manager, MMModem *modem) g_free (device); } +/* Return the first outstanding supports task */ +static SupportsInfo * +find_supports_info (MMManager *self, MMModem *modem) +{ + char *modem_physdev; + GHashTableIter iter; + SupportsInfo *info, *ret = NULL; + + modem_physdev = mm_modem_get_device (modem); + g_assert (modem_physdev); + + /* Check for ports that are in the process of being interrogated by plugins */ + g_hash_table_iter_init (&iter, MM_MANAGER_GET_PRIVATE (self)->supports); + while (!ret && g_hash_table_iter_next (&iter, NULL, (gpointer) &info)) { + if (g_strcmp0 (info->physdev_path, modem_physdev) == 0) + ret = info; + } + g_free (modem_physdev); + return ret; +} + static void check_export_modem (MMManager *self, MMModem *modem) { MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (self); - char *modem_physdev; - GHashTableIter iter; - gpointer value; + SupportsInfo *info; + static guint32 id = 0, vid = 0, pid = 0; + char *path, *data_device = NULL, *modem_physdev; + GUdevDevice *physdev; + const char *subsys = NULL; /* A modem is only exported to D-Bus when both of the following are true: * @@ -269,63 +292,46 @@ check_export_modem (MMManager *self, MMModem *modem) * all other ports are already handled. That chance is very small though. */ - modem_physdev = mm_modem_get_device (modem); - g_assert (modem_physdev); - - /* Check for ports that are in the process of being interrogated by plugins */ - g_hash_table_iter_init (&iter, priv->supports); - while (g_hash_table_iter_next (&iter, NULL, &value)) { - SupportsInfo *info = value; - - if (!strcmp (info->physdev_path, modem_physdev)) { - mm_dbg ("(%s/%s): outstanding support task prevents export of %s", - info->subsys, info->name, modem_physdev); - goto out; - } + info = find_supports_info (self, modem); + if (info) { + mm_dbg ("(%s/%s): outstanding support task prevents export of %s", + info->subsys, info->name, info->physdev_path); + return; } - /* Already exported? This can happen if the modem is exported and the kernel - * discovers another of the modem's ports. - */ - if (g_object_get_data (G_OBJECT (modem), DBUS_PATH_TAG)) - goto out; + /* Obviously don't re-export a modem, or try to export one that's not valid */ + if ( g_object_get_data (G_OBJECT (modem), DBUS_PATH_TAG) + || !mm_modem_get_valid (modem)) + return; + + path = g_strdup_printf (MM_DBUS_PATH "/Modems/%d", id++); + dbus_g_connection_register_g_object (priv->connection, path, G_OBJECT (modem)); + g_object_set_data_full (G_OBJECT (modem), DBUS_PATH_TAG, path, (GDestroyNotify) g_free); - /* No outstanding port tasks, so if the modem is valid we can export it */ - if (mm_modem_get_valid (modem)) { - static guint32 id = 0, vid = 0, pid = 0; - char *path, *data_device = NULL; - GUdevDevice *physdev; - const char *subsys = NULL; - - path = g_strdup_printf (MM_DBUS_PATH"/Modems/%d", id++); - dbus_g_connection_register_g_object (priv->connection, path, G_OBJECT (modem)); - g_object_set_data_full (G_OBJECT (modem), DBUS_PATH_TAG, path, (GDestroyNotify) g_free); - - mm_dbg ("Exported modem %s as %s", modem_physdev, path); - - physdev = g_udev_client_query_by_sysfs_path (priv->udev, modem_physdev); - if (physdev) - subsys = g_udev_device_get_subsystem (physdev); - - g_object_get (G_OBJECT (modem), - MM_MODEM_DATA_DEVICE, &data_device, - MM_MODEM_HW_VID, &vid, - MM_MODEM_HW_PID, &pid, - NULL); - mm_dbg ("(%s): VID 0x%04X PID 0x%04X (%s)", - path, (vid & 0xFFFF), (pid & 0xFFFF), - subsys ? subsys : "unknown"); - mm_dbg ("(%s): data port is %s", path, data_device); - g_free (data_device); - - if (physdev) - g_object_unref (physdev); - - g_signal_emit (self, signals[DEVICE_ADDED], 0, modem); - } + modem_physdev = mm_modem_get_device (modem); + g_assert (modem_physdev); + mm_dbg ("Exported modem %s as %s", modem_physdev, path); -out: + physdev = g_udev_client_query_by_sysfs_path (priv->udev, modem_physdev); g_free (modem_physdev); + if (physdev) + subsys = g_udev_device_get_subsystem (physdev); + + g_object_get (G_OBJECT (modem), + MM_MODEM_DATA_DEVICE, &data_device, + MM_MODEM_HW_VID, &vid, + MM_MODEM_HW_PID, &pid, + NULL); + mm_dbg ("(%s): VID 0x%04X PID 0x%04X (%s)", + path, (vid & 0xFFFF), (pid & 0xFFFF), + subsys ? subsys : "unknown"); + mm_dbg ("(%s): data port is %s", path, data_device); + g_free (data_device); + + if (physdev) + g_object_unref (physdev); + + g_signal_emit (self, signals[DEVICE_ADDED], 0, modem); } static void @@ -548,6 +554,7 @@ supports_cleanup (MMManager *self, { MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (self); char *key; + GError *error = NULL; g_return_if_fail (subsys != NULL); g_return_if_fail (name != NULL); @@ -556,15 +563,35 @@ supports_cleanup (MMManager *self, g_hash_table_remove (priv->supports, key); g_free (key); + if (modem == NULL) + return; + + if ( (find_supports_info (self, modem) == NULL) + && !g_object_get_data (G_OBJECT (modem), "organized")) { + /* Yay, we're done with supports tasks, tell the modem to organize + * all its ports. Guard against multiple organize calls though since + * if the kernel or udev is slow, ports may show up long after the + * first bunch of supports tasks is done. + */ + g_object_set_data (G_OBJECT (modem), "organized", GUINT_TO_POINTER (1)); + if (!mm_modem_organize_ports (modem, &error)) { + mm_err ("Failed to organize modem ports: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + remove_modem (self, modem); + return; + } + } + /* Each time a supports task is cleaned up, check whether the modem is * now completely probed/handled and should be exported to D-Bus clients. * - * IMPORTANT: this must be done after removing the supports into from + * IMPORTANT: this must be done after removing the supports info from * priv->supports since check_export_modem() searches through priv->supports * for outstanding supports tasks. */ - if (modem) - check_export_modem (self, modem); + check_export_modem (self, modem); } static gboolean |