aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@gnu.org>2011-09-15 21:27:11 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-03-15 14:14:21 +0100
commita67d5dc1b84db6cc1517475b90a047d6d9a19968 (patch)
tree85f73d02e3f621486bd0f96446da43aaeec729a0
parent7b687b4aae5c1fc89b9203bd43602b4820042d7c (diff)
plugin-base: make the plugin base use the new port probing mechanism
The previous 'MMPluginBaseSupportsTask' object is more or less equivalent to the new `MMPortProbe' in terms of what information it contains. The main difference being that the new `MMPortProbe' object handles internally the whole probing flow as needed: only the needed probing sequences are done. For example, vendor or product string probing will only be performed if a plugin requests it.
-rw-r--r--src/mm-plugin-base.c1285
-rw-r--r--src/mm-plugin-base.h125
2 files changed, 99 insertions, 1311 deletions
diff --git a/src/mm-plugin-base.c b/src/mm-plugin-base.c
index 78cf9640..c5fe8d49 100644
--- a/src/mm-plugin-base.c
+++ b/src/mm-plugin-base.c
@@ -28,7 +28,7 @@
#include <gudev/gudev.h>
#include "mm-plugin-base.h"
-#include "mm-port-probe.h"
+#include "mm-port-probe-cache.h"
#include "mm-at-serial-port.h"
#include "mm-qcdm-serial-port.h"
#include "mm-serial-parsers.h"
@@ -47,24 +47,11 @@ G_DEFINE_TYPE_EXTENDED (MMPluginBase, mm_plugin_base, G_TYPE_OBJECT,
#define MM_PLUGIN_BASE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_PLUGIN_BASE, MMPluginBasePrivate))
-/* Struct to be stored in the cached hash table */
-typedef struct {
- guint32 capabilities;
- gchar *vendor;
- gchar *product;
-} MMPluginBaseProbedInfo;
-
-/* A hash table shared between all instances of the plugin base that
- * caches the probed capabilities and reported vendor/model (when available)
- * so that only one plugin has to actually probe a port.
- */
-static GHashTable *probed_info = NULL;
-
/* Virtual port corresponding to the embeded modem */
static gchar *virtual_port[] = {"smd0", NULL};
typedef struct {
- char *name;
+ gchar *name;
GUdevClient *client;
GHashTable *tasks;
gboolean sort_last;
@@ -101,1071 +88,8 @@ enum {
LAST_PROP
};
-enum {
- PROBE_RESULT,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-typedef enum {
- /* Probing capabilities... */
- PROBE_STATE_CAPS_GCAP_TRY1 = 0,
- PROBE_STATE_CAPS_GCAP_TRY2,
- PROBE_STATE_CAPS_GCAP_TRY3,
- PROBE_STATE_CAPS_ATI,
- PROBE_STATE_CAPS_CPIN,
- PROBE_STATE_CAPS_CGMM,
- /* Probing vendor... */
- PROBE_STATE_VENDOR_CGMI,
- PROBE_STATE_VENDOR_GMI,
- PROBE_STATE_VENDOR_ATI,
- /* Probing product... */
- PROBE_STATE_PRODUCT_CGMM,
- PROBE_STATE_PRODUCT_GMM,
- PROBE_STATE_PRODUCT_ATI,
- PROBE_STATE_LAST
-} ProbeState;
-
-/* Additional helper IDs for the states, to be updated whenever new intermediate
- * states are added in each probing group */
-#define PROBE_STATE_CAPS_FIRST PROBE_STATE_CAPS_GCAP_TRY1
-#define PROBE_STATE_CAPS_LAST PROBE_STATE_CAPS_CGMM
-#define PROBE_STATE_VENDOR_FIRST PROBE_STATE_VENDOR_CGMI
-#define PROBE_STATE_VENDOR_LAST PROBE_STATE_VENDOR_ATI
-#define PROBE_STATE_PRODUCT_FIRST PROBE_STATE_PRODUCT_CGMM
-#define PROBE_STATE_PRODUCT_LAST PROBE_STATE_PRODUCT_ATI
-
-typedef struct {
- /* The command to send in this probing state */
- gchar *cmd;
- /* Whether the command reply should be cached */
- gboolean cached;
-} ProbeStateCmd;
-
-/* List of commands sent in each state */
-static const ProbeStateCmd state_commands[PROBE_STATE_LAST] = {
- /* Probing capabilities... */
- { "+GCAP", FALSE }, /* PROBE_STATE_CAPS_GCAP_TRY1 */
- { "+GCAP", FALSE }, /* PROBE_STATE_CAPS_GCAP_TRY2 */
- { "+GCAP", FALSE }, /* PROBE_STATE_CAPS_GCAP_TRY3 */
- { "I", TRUE }, /* PROBE_STATE_CAPS_ATI */
- { "+CPIN?", FALSE }, /* PROBE_STATE_CAPS_CPIN */
- { "+CGMM", TRUE }, /* PROBE_STATE_CAPS_CGMM */
- /* Probing vendor... */
- { "+CGMI", TRUE }, /* PROBE_STATE_VENDOR_CGMI */
- { "+GMI", TRUE }, /* PROBE_STATE_VENDOR_GMI */
- { "I", TRUE }, /* PROBE_STATE_VENDOR_ATI */
- /* Probing product... */
- { "+CGMM", TRUE }, /* PROBE_STATE_PRODUCT_CGMM */
- { "+GMM", TRUE }, /* PROBE_STATE_PRODUCT_GMM */
- { "I", TRUE } /* PROBE_STATE_PRODUCT_ATI */
-};
-
-static void probe_complete (MMPluginBaseSupportsTask *task);
-static void parse_response (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data);
-
-/*****************************************************************************/
-
-G_DEFINE_TYPE (MMPluginBaseSupportsTask, mm_plugin_base_supports_task, G_TYPE_OBJECT)
-
-#define MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK, MMPluginBaseSupportsTaskPrivate))
-
-typedef struct {
- MMPluginSupportsResult result;
- guint support_level;
-} SupportsPortResult;
-
-typedef struct {
- char *command;
- guint32 tries;
- guint32 delay_seconds;
- MMBaseSupportsTaskCustomInitResultFunc callback;
- gpointer callback_data;
-} CustomInit;
-
-typedef struct {
- MMPluginBase *plugin;
- GUdevDevice *port;
- char *physdev_path;
- char *driver;
-
- guint open_id;
- guint32 open_tries;
- guint full_id;
-
- MMAtSerialPort *probe_port;
- MMQcdmSerialPort *qcdm_port;
- guint32 probed_caps;
- gchar *probed_vendor;
- gchar *probed_product;
- ProbeState probe_state;
- guint probe_id;
- char *probe_resp;
- GError *probe_error;
-
- /* Custom init commands plugins might want */
- GSList *custom;
- GSList *cur_custom; /* Pointer to current custom init command */
-
- GSimpleAsyncResult *async_result;
-} MMPluginBaseSupportsTaskPrivate;
-
-static SupportsPortResult *supports_port_result_new (MMPluginSupportsResult result,
- guint support_level);
-static void supports_port_result_free (SupportsPortResult *spr);
-
-static MMPluginBaseSupportsTask *
-supports_task_new (MMPluginBase *self,
- GUdevDevice *port,
- const char *physdev_path,
- const char *driver,
- GSimpleAsyncResult *result)
-{
- MMPluginBaseSupportsTask *task;
- MMPluginBaseSupportsTaskPrivate *priv;
-
- task = (MMPluginBaseSupportsTask *) g_object_new (MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK, NULL);
-
- priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
- priv->plugin = self;
- priv->port = g_object_ref (port);
- priv->physdev_path = g_strdup (physdev_path);
- priv->driver = g_strdup (driver);
- priv->async_result = g_object_ref (result);
-
- return task;
-}
-
-MMPlugin *
-mm_plugin_base_supports_task_get_plugin (MMPluginBaseSupportsTask *task)
-{
- g_return_val_if_fail (task != NULL, NULL);
- g_return_val_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task), NULL);
-
- return MM_PLUGIN (MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task)->plugin);
-}
-
-GUdevDevice *
-mm_plugin_base_supports_task_get_port (MMPluginBaseSupportsTask *task)
-{
- g_return_val_if_fail (task != NULL, NULL);
- g_return_val_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task), NULL);
-
- return MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task)->port;
-}
-
-const char *
-mm_plugin_base_supports_task_get_physdev_path (MMPluginBaseSupportsTask *task)
-{
- g_return_val_if_fail (task != NULL, NULL);
- g_return_val_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task), NULL);
-
- return MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task)->physdev_path;
-}
-
-const char *
-mm_plugin_base_supports_task_get_driver (MMPluginBaseSupportsTask *task)
-{
- g_return_val_if_fail (task != NULL, NULL);
- g_return_val_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task), NULL);
-
- return MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task)->driver;
-}
-
-guint32
-mm_plugin_base_supports_task_get_probed_capabilities (MMPluginBaseSupportsTask *task)
-{
- g_return_val_if_fail (task != NULL, 0);
- g_return_val_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task), 0);
-
- return MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task)->probed_caps;
-}
-
-MMPortType
-mm_plugin_base_probed_capabilities_to_port_type (guint32 caps)
-{
- if (caps & MM_PLUGIN_BASE_PORT_CAP_AT)
- return MM_PORT_TYPE_AT;
- else if (caps & MM_PLUGIN_BASE_PORT_CAP_QCDM)
- return MM_PORT_TYPE_QCDM;
- return MM_PORT_TYPE_UNKNOWN;
-}
-
-const gchar *
-mm_plugin_base_supports_task_get_probed_vendor (MMPluginBaseSupportsTask *task)
-{
- g_return_val_if_fail (task != NULL, NULL);
- g_return_val_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task), NULL);
-
- return MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task)->probed_vendor;
-}
-
-const gchar *
-mm_plugin_base_supports_task_get_probed_product (MMPluginBaseSupportsTask *task)
-{
- g_return_val_if_fail (task != NULL, NULL);
- g_return_val_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task), NULL);
-
- return MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task)->probed_product;
-}
-
-gboolean
-mm_plugin_base_supports_task_propagate_cached (MMPluginBaseSupportsTask *task)
-{
- MMPluginBaseSupportsTaskPrivate *priv;
-
- g_return_val_if_fail (task != NULL, FALSE);
- g_return_val_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task), FALSE);
-
- priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
-
- g_free (priv->probed_vendor);
- g_free (priv->probed_product);
-
- /* Returns TRUE if a previous supports task already cached probing results.
- * It will also store a copy of the cached result. */
- return mm_plugin_base_get_cached_probe_result (priv->plugin,
- priv->port,
- &priv->probed_caps,
- &priv->probed_vendor,
- &priv->probed_product);
-}
-
-void
-mm_plugin_base_supports_task_complete (MMPluginBaseSupportsTask *task,
- guint32 level)
-{
- MMPluginBaseSupportsTaskPrivate *priv;
-
- g_return_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task));
-
- priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
-
- if (priv->full_id) {
- g_source_remove (priv->full_id);
- priv->full_id = 0;
- }
-
- g_simple_async_result_set_op_res_gpointer (
- priv->async_result,
- supports_port_result_new ((level > 0 ?
- MM_PLUGIN_SUPPORTS_PORT_SUPPORTED :
- MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED),
- level),
- (GDestroyNotify)supports_port_result_free);
- g_simple_async_result_complete (priv->async_result);
-}
-
-void
-mm_plugin_base_supports_task_add_custom_init_command (MMPluginBaseSupportsTask *task,
- const char *cmd,
- guint32 delay_seconds,
- MMBaseSupportsTaskCustomInitResultFunc callback,
- gpointer callback_data)
-{
- MMPluginBaseSupportsTaskPrivate *priv;
- CustomInit *custom;
-
- g_return_if_fail (task != NULL);
- g_return_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task));
- g_return_if_fail (callback != NULL);
-
- priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
-
- custom = g_malloc0 (sizeof (*custom));
- custom->command = g_strdup (cmd);
- custom->delay_seconds = delay_seconds ? delay_seconds : 3;
- custom->callback = callback;
- custom->callback_data = callback_data;
-
- priv->custom = g_slist_append (priv->custom, custom);
-}
-
-static void
-mm_plugin_base_supports_task_init (MMPluginBaseSupportsTask *self)
-{
-}
-
-static void
-supports_task_dispose (GObject *object)
-{
- MMPluginBaseSupportsTaskPrivate *priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (object);
- GSList *iter;
-
- if (MM_IS_SERIAL_PORT (priv->probe_port))
- mm_serial_port_flash_cancel (MM_SERIAL_PORT (priv->probe_port));
-
- g_object_unref (priv->port);
- g_free (priv->physdev_path);
- g_free (priv->driver);
-
- for (iter = priv->custom; iter; iter = g_slist_next (iter)) {
- CustomInit *custom = iter->data;
-
- g_free (custom->command);
- memset (custom, 0, sizeof (*custom));
- g_free (custom);
- }
-
- if (priv->open_id)
- g_source_remove (priv->open_id);
- if (priv->full_id)
- g_source_remove (priv->full_id);
-
- if (priv->probe_id)
- g_source_remove (priv->probe_id);
- if (priv->probe_port) {
- mm_serial_port_close (MM_SERIAL_PORT (priv->probe_port));
- g_object_unref (priv->probe_port);
- }
- if (priv->qcdm_port) {
- mm_serial_port_close (MM_SERIAL_PORT (priv->qcdm_port));
- g_object_unref (priv->qcdm_port);
- }
-
- g_free (priv->probed_vendor);
- g_free (priv->probed_product);
- g_free (priv->probe_resp);
- g_clear_error (&(priv->probe_error));
-
- G_OBJECT_CLASS (mm_plugin_base_supports_task_parent_class)->dispose (object);
-}
-
-static void
-mm_plugin_base_supports_task_class_init (MMPluginBaseSupportsTaskClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (object_class, sizeof (MMPluginBaseSupportsTaskPrivate));
-
- /* Virtual methods */
- object_class->dispose = supports_task_dispose;
-}
-
-/*****************************************************************************/
-
-#define MM_PLUGIN_BASE_PORT_CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
- MM_PLUGIN_BASE_PORT_CAP_IS707_P | \
- MM_PLUGIN_BASE_PORT_CAP_IS856 | \
- MM_PLUGIN_BASE_PORT_CAP_IS856_A)
-
-#define CAP_GSM_OR_CDMA (MM_PLUGIN_BASE_PORT_CAP_CDMA | MM_PLUGIN_BASE_PORT_CAP_GSM)
-
-struct modem_caps {
- char *name;
- guint32 bits;
-};
-
-static struct modem_caps modem_caps[] = {
- {"+CGSM", MM_PLUGIN_BASE_PORT_CAP_GSM},
- {"+CIS707-A", MM_PLUGIN_BASE_PORT_CAP_IS707_A},
- {"+CIS707A", MM_PLUGIN_BASE_PORT_CAP_IS707_A}, /* Cmotech */
- {"+CIS707", MM_PLUGIN_BASE_PORT_CAP_IS707_A},
- {"CIS707", MM_PLUGIN_BASE_PORT_CAP_IS707_A}, /* Qualcomm Gobi */
- {"+CIS707P", MM_PLUGIN_BASE_PORT_CAP_IS707_P},
- {"CIS-856", MM_PLUGIN_BASE_PORT_CAP_IS856},
- {"+IS-856", MM_PLUGIN_BASE_PORT_CAP_IS856}, /* Cmotech */
- {"CIS-856-A", MM_PLUGIN_BASE_PORT_CAP_IS856_A},
- {"CIS-856A", MM_PLUGIN_BASE_PORT_CAP_IS856_A}, /* Kyocera KPC680 */
- {"+DS", MM_PLUGIN_BASE_PORT_CAP_DS},
- {"+ES", MM_PLUGIN_BASE_PORT_CAP_ES},
- {"+MS", MM_PLUGIN_BASE_PORT_CAP_MS},
- {"+FCLASS", MM_PLUGIN_BASE_PORT_CAP_FCLASS},
- {"+WIRIDIUM", MM_PLUGIN_BASE_PORT_CAP_IRIDIUM},
- {NULL}
-};
-
-static guint32
-parse_caps_gcap (const char *buf)
-{
- struct modem_caps *cap = modem_caps;
- guint32 ret = 0;
-
- while (cap->name) {
- if (strstr (buf, cap->name))
- ret |= cap->bits;
- cap++;
- }
- return ret;
-}
-
-static guint32
-parse_caps_cpin (const char *buf)
-{
- if ( strcasestr (buf, "SIM PIN")
- || strcasestr (buf, "SIM PUK")
- || strcasestr (buf, "PH-SIM PIN")
- || strcasestr (buf, "PH-FSIM PIN")
- || strcasestr (buf, "PH-FSIM PUK")
- || strcasestr (buf, "SIM PIN2")
- || strcasestr (buf, "SIM PUK2")
- || strcasestr (buf, "PH-NET PIN")
- || strcasestr (buf, "PH-NET PUK")
- || strcasestr (buf, "PH-NETSUB PIN")
- || strcasestr (buf, "PH-NETSUB PUK")
- || strcasestr (buf, "PH-SP PIN")
- || strcasestr (buf, "PH-SP PUK")
- || strcasestr (buf, "PH-CORP PIN")
- || strcasestr (buf, "PH-CORP PUK")
- || strcasestr (buf, "READY"))
- return MM_PLUGIN_BASE_PORT_CAP_GSM;
-
- return 0;
-}
-
-static guint32
-parse_caps_cgmm (const char *buf)
-{
- if (strstr (buf, "GSM900") || strstr (buf, "GSM1800") ||
- strstr (buf, "GSM1900") || strstr (buf, "GSM850"))
- return MM_PLUGIN_BASE_PORT_CAP_GSM;
- return 0;
-}
-
-static gchar *
-parse_vendor_cgmi (const gchar *buf)
-{
- return g_strstrip (g_strdelimit (g_strdup (buf), "\r\n", ' '));
-}
-
-static gchar *
-parse_product_cgmm (const gchar *buf)
-{
- return g_strstrip (g_strdelimit (g_strdup (buf), "\r\n", ' '));
-}
-
-static const char *dq_strings[] = {
- /* Option Icera-based devices */
- "option/faema_",
- "os_logids.h",
- /* Sierra CnS port */
- "NETWORK SERVICE CHANGE",
- "/SRC/AMSS",
- NULL
-};
-
-static guint8 zerobuf[32] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-static void
-probed_info_free (MMPluginBaseProbedInfo *info)
-{
- if (!info)
- return;
-
- g_free (info->vendor);
- g_free (info->product);
- g_free (info);
-}
-
-static void
-port_buffer_full (MMSerialPort *port, GByteArray *buffer, gpointer user_data)
-{
- MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data);
- MMPluginBaseSupportsTaskPrivate *priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (user_data);
- const char **iter;
- size_t iter_len;
- int i;
-
- /* Some devices (observed on a ZTE branded "QUALCOMM INCORPORATED" model
- * "154") spew NULLs from some ports.
- */
- if ( (buffer->len >= sizeof (zerobuf))
- && (memcmp (buffer->data, zerobuf, sizeof (zerobuf)) == 0))
- goto stop_probing;
-
- /* Check for an immediate disqualification response. There are some
- * ports (Option Icera-based chipsets have them, as do Qualcomm Gobi
- * devices before their firmware is loaded) that just shouldn't be
- * probed if we get a certain response because we know they can't be
- * used. Kernel bugs (at least with 2.6.31 and 2.6.32) also trigger port
- * flow control kernel oopses if we read too much data for these ports.
- */
-
- for (iter = &dq_strings[0]; iter && *iter; iter++) {
- /* Search in the response for the item; the response could have embedded
- * nulls so we can't use memcmp() or strstr() on the whole response.
- */
- iter_len = strlen (*iter);
- for (i = 0; i < buffer->len - iter_len; i++) {
- if (!memcmp (&buffer->data[i], *iter, iter_len)) {
- /* Immediately close the port and complete probing */
- goto stop_probing;
- }
- }
- }
- return;
-
-stop_probing:
- priv->probed_caps = 0;
- priv->probed_vendor = NULL;
- priv->probed_product = NULL;
- mm_serial_port_close (MM_SERIAL_PORT (priv->probe_port));
- probe_complete (task);
-}
-
-static gboolean
-emit_probe_result (gpointer user_data)
-{
- MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data);
- MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
- MMPlugin *self = mm_plugin_base_supports_task_get_plugin (task);
-
- /* Close the serial ports */
- if (task_priv->probe_port) {
- g_object_unref (task_priv->probe_port);
- task_priv->probe_port = NULL;
- }
- if (task_priv->qcdm_port) {
- g_object_unref (task_priv->qcdm_port);
- task_priv->qcdm_port = NULL;
- }
-
- task_priv->probe_id = 0;
- g_signal_emit (self, signals[PROBE_RESULT], 0, task, task_priv->probed_caps);
- return FALSE;
-}
-
-static void
-probe_complete (MMPluginBaseSupportsTask *task)
-{
- MMPluginBaseSupportsTaskPrivate *priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
- MMPluginBaseProbedInfo *info;
- MMPort *port;
-
- port = priv->probe_port ? MM_PORT (priv->probe_port) : MM_PORT (priv->qcdm_port);
- g_assert (port);
-
- /* Allocate new cached info struct and store it in the hash table */
- info = g_malloc0 (sizeof (*info));
- info->capabilities = priv->probed_caps;
- info->vendor = g_strdup (priv->probed_vendor);
- info->product = g_strdup (priv->probed_product);
- g_hash_table_insert (probed_info,
- g_strdup (mm_port_get_device (port)),
- info);
-
- priv->probe_id = g_idle_add (emit_probe_result, task);
-}
-
-static void
-qcdm_verinfo_cb (MMQcdmSerialPort *port,
- GByteArray *response,
- GError *error,
- gpointer user_data)
-{
- MMPluginBaseSupportsTask *task;
- MMPluginBaseSupportsTaskPrivate *priv;
- QcdmResult *result;
- int err = QCDM_SUCCESS;
-
- /* Just the initial poke; ignore it */
- if (!user_data)
- return;
-
- task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data);
- priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
-
- if (error) {
- /* Probably not a QCDM port */
- goto done;
- }
-
- /* Parse the response */
- result = qcdm_cmd_version_info_result ((const char *) response->data, response->len, &err);
- if (!result) {
- g_warning ("(%s) failed to parse QCDM version info command result: %d",
- g_udev_device_get_name (priv->port), err);
- goto done;
- }
-
- /* yay, probably a QCDM port */
- qcdm_result_unref (result);
- priv->probed_caps |= MM_PLUGIN_BASE_PORT_CAP_QCDM;
-done:
- probe_complete (task);
-}
-
-static void
-try_qcdm_probe (MMPluginBaseSupportsTask *task)
-{
- MMPluginBaseSupportsTaskPrivate *priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
- const char *name;
- GError *error = NULL;
- GByteArray *verinfo = NULL, *verinfo2;
- gint len;
-
- /* Close the AT port */
- if (priv->probe_port) {
- mm_serial_port_close (MM_SERIAL_PORT (priv->probe_port));
- g_object_unref (priv->probe_port);
- priv->probe_port = NULL;
- }
-
- /* Open the QCDM port */
- name = g_udev_device_get_name (priv->port);
- g_assert (name);
- priv->qcdm_port = mm_qcdm_serial_port_new (name);
- if (priv->qcdm_port == NULL) {
- g_warning ("(%s) failed to create new QCDM serial port.", name);
- probe_complete (task);
- return;
- }
-
- if (!mm_serial_port_open (MM_SERIAL_PORT (priv->qcdm_port), &error)) {
- g_warning ("(%s) failed to open new QCDM serial port: (%d) %s.",
- name,
- error ? error->code : -1,
- error && error->message ? error->message : "(unknown)");
- g_clear_error (&error);
- probe_complete (task);
- return;
- }
-
- /* Build up the probe command */
- verinfo = g_byte_array_sized_new (50);
- len = qcdm_cmd_version_info_new ((char *) verinfo->data, 50);
- if (len <= 0) {
- g_byte_array_free (verinfo, TRUE);
- g_warning ("(%s) failed to create QCDM version info command", name);
- probe_complete (task);
- return;
- }
- verinfo->len = len;
-
- /* Queuing the command takes ownership over it; copy 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 (priv->qcdm_port, verinfo, 3, qcdm_verinfo_cb, NULL);
- mm_qcdm_serial_port_queue_command (priv->qcdm_port, verinfo2, 3, qcdm_verinfo_cb, task);
-}
-
-static void
-real_handle_probe_response (MMPluginBase *self,
- MMPluginBaseSupportsTask *task,
- const char *cmd,
- const char *response,
- const GError *error)
-{
- MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
- MMAtSerialPort *port = task_priv->probe_port;
-
- /* Some modems (Huawei E160g) won't respond to +GCAP with no SIM, but
- * will respond to ATI. Ignore the error and continue.
- */
- if (response && strstr (response, "+CME ERROR:")) {
- task_priv->probed_caps |= MM_PLUGIN_BASE_PORT_CAP_AT;
- error = NULL;
- }
-
- if (error) {
- /* If the modem returned a recognizable error, it can do AT commands */
- if (error->domain == MM_MOBILE_ERROR)
- task_priv->probed_caps |= MM_PLUGIN_BASE_PORT_CAP_AT;
-
- /* Only allow timeout errors in the initial AT+GCAP queries. If all AT+GCAP
- * get timed out, assume it's not an AT port. */
- if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) {
- /* Try GCAP again */
- if (task_priv->probe_state < PROBE_STATE_CAPS_GCAP_TRY3) {
- task_priv->probe_state++;
- mm_at_serial_port_queue_command (port,
- state_commands[task_priv->probe_state].cmd,
- 3,
- parse_response,
- task);
- return;
- }
-
- /* If all the GCAP tries timed out, ignore the port as it's
- * probably not an AT-capable port. Try QCDM.
- */
- if (task_priv->probe_state == PROBE_STATE_CAPS_GCAP_TRY3) {
- try_qcdm_probe (task);
- return;
- }
-
- /* Otherwise, it's a timeout in some other command being probed, so try the
- * next one if any */
- }
-
- /* Non-timeout error, so proceed to the next command if any */
- } else if (response) {
- /* Parse the response */
-
- switch (task_priv->probe_state) {
- case PROBE_STATE_CAPS_GCAP_TRY1:
- case PROBE_STATE_CAPS_GCAP_TRY2:
- case PROBE_STATE_CAPS_GCAP_TRY3:
- case PROBE_STATE_CAPS_ATI:
- /* Some modems don't respond to AT+GCAP, but often they put a
- * GCAP-style response as a line in the ATI response.
- */
- task_priv->probed_caps |= parse_caps_gcap (response);
- task_priv->probed_caps |= MM_PLUGIN_BASE_PORT_CAP_AT;
- break;
- case PROBE_STATE_CAPS_CPIN:
- /* Some devices (ZTE MF628/ONDA MT503HS for example) reply to
- * anything but AT+CPIN? with ERROR if the device has a PIN set.
- * Since no known CDMA modems support AT+CPIN? we can consider the
- * device a GSM device if it returns a non-error response to AT+CPIN?.
- */
- task_priv->probed_caps |= parse_caps_cpin (response);
- task_priv->probed_caps |= MM_PLUGIN_BASE_PORT_CAP_AT;
- break;
- case PROBE_STATE_CAPS_CGMM:
- /* Some models (BUSlink SCWi275u) stick stupid stuff in the CGMM
- * response but at least it allows us to identify them.
- */
- task_priv->probed_caps |= parse_caps_cgmm (response);
- task_priv->probed_caps |= MM_PLUGIN_BASE_PORT_CAP_AT;
- break;
- case PROBE_STATE_VENDOR_CGMI:
- case PROBE_STATE_VENDOR_GMI:
- case PROBE_STATE_VENDOR_ATI:
- /* These replies parsed the same way, just removing EOLs */
- task_priv->probed_vendor = parse_vendor_cgmi (response);
- break;
- case PROBE_STATE_PRODUCT_CGMM:
- case PROBE_STATE_PRODUCT_GMM:
- case PROBE_STATE_PRODUCT_ATI:
- /* These replies parsed the same way, just removing EOLs */
- task_priv->probed_product = parse_product_cgmm (response);
- break;
- default:
- break;
- }
- }
-
- /* Now, choose the proper next state */
-
- if (task_priv->probe_state <= PROBE_STATE_CAPS_LAST) {
- /* Probing capabilities */
- if (task_priv->probed_caps & CAP_GSM_OR_CDMA) {
- /* Got capabilities probed, go on with vendor probing */
- task_priv->probe_state = PROBE_STATE_VENDOR_FIRST;
- } else if (task_priv->probe_state < PROBE_STATE_CAPS_LAST) {
- /* Didn't get capabilities probed yet, go on to next caps
- * probing command */
- task_priv->probe_state++;
- } else {
- /* Tried probing all commands for capabilities and didn't get
- * any: just end probing here, it probably isn't a GSM or CDMA
- * modem */
- mm_warn ("Couldn't probe for capabilities, probably not a GSM or CDMA modem");
- probe_complete (task);
- return;
- }
- } else if (task_priv->probe_state <= PROBE_STATE_VENDOR_LAST) {
- /* Probing vendors */
- if (task_priv->probed_vendor) {
- /* Got vendor probed, go on with product probing. */
- task_priv->probe_state = PROBE_STATE_PRODUCT_FIRST;
- } else if (task_priv->probe_state < PROBE_STATE_VENDOR_LAST) {
- /* Didn't get vendor probed yet, go on to next vendor
- * probing command */
- task_priv->probe_state++;
- } else {
- /* Tried probing all commands for vendor and didn't get
- * any: just end probing here, product ID is useless without
- * vendor ID */
- probe_complete (task);
- return;
- }
- } else if (task_priv->probe_state <= PROBE_STATE_PRODUCT_LAST) {
- /* Probing products */
- if (!task_priv->probed_product &&
- task_priv->probe_state < PROBE_STATE_PRODUCT_LAST) {
- /* Didn't get probed product yet but more commands available,
- * go on with the next one */
- task_priv->probe_state++;
- } else {
- /* Got product probed or no more commands to probe, so end. */
- probe_complete (task);
- return;
- }
- } else {
- g_warn_if_reached ();
- }
-
- /* Out of last state? */
- if (task_priv->probe_state >= PROBE_STATE_LAST) {
- /* Probing ended */
- probe_complete (task);
- return;
- }
-
- /* Go on with the command in next state */
-
- if (state_commands[task_priv->probe_state].cached)
- mm_at_serial_port_queue_command_cached (port,
- state_commands[task_priv->probe_state].cmd,
- 3,
- parse_response,
- task);
- else
- mm_at_serial_port_queue_command (port,
- state_commands[task_priv->probe_state].cmd,
- 3,
- parse_response,
- task);
-}
-
-static gboolean
-handle_probe_response (gpointer user_data)
-{
- MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data);
- MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
- MMPluginBase *self = MM_PLUGIN_BASE (mm_plugin_base_supports_task_get_plugin (task));
-
- MM_PLUGIN_BASE_GET_CLASS (self)->handle_probe_response (self,
- task,
- state_commands[task_priv->probe_state].cmd,
- task_priv->probe_resp,
- task_priv->probe_error);
- return FALSE;
-}
-
-static void
-parse_response (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data);
- MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
-
- if (task_priv->probe_id)
- g_source_remove (task_priv->probe_id);
- g_free (task_priv->probe_resp);
- task_priv->probe_resp = NULL;
- g_clear_error (&(task_priv->probe_error));
-
- if (response && response->len)
- task_priv->probe_resp = g_strdup (response->str);
- if (error)
- task_priv->probe_error = g_error_copy (error);
-
- /* Schedule the response handler in an idle, since we can't emit the
- * PROBE_RESULT signal from the serial port response handler without
- * potentially destroying the serial port in the middle of its response
- * handler, which it understandably doesn't like.
- */
- task_priv->probe_id = g_idle_add (handle_probe_response, task);
-}
-
-static void
-start_generic_probing (MMPluginBaseSupportsTask *task, MMAtSerialPort *port)
-{
- mm_at_serial_port_queue_command (port, "+GCAP", 3, parse_response, task);
-}
-
-static void flash_done (MMSerialPort *port, GError *error, gpointer user_data);
-
-static void
-custom_init_response (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data);
- MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
- CustomInit *custom = task_priv->cur_custom->data;
- gboolean retry = FALSE;
- gboolean stop = FALSE;
- guint32 level = 0;
-
- custom->tries++;
- retry = custom->callback (task, response, error, custom->tries, &stop, &level, custom->callback_data);
-
- if (stop) {
- task_priv->probed_caps = level;
- probe_complete (task);
- return;
- }
-
- if (retry) {
- /* Try the custom command again */
- flash_done (MM_SERIAL_PORT (port), NULL, task);
- return;
- }
-
- /* Any more custom init commands? */
- task_priv->cur_custom = g_slist_next (task_priv->cur_custom);
- if (task_priv->cur_custom) {
- /* There are more custom init commands */
- flash_done (MM_SERIAL_PORT (port), NULL, task);
- return;
- }
-
- /* Otherwise continue with generic probing */
- start_generic_probing (task, port);
-}
-
-static void
-flash_done (MMSerialPort *port, GError *error, gpointer user_data)
-{
- MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data);
- MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
-
- /* Send the custom init command if any */
- if (task_priv->cur_custom) {
- CustomInit *custom = task_priv->cur_custom->data;
-
- mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port),
- custom->command,
- custom->delay_seconds,
- custom_init_response,
- task);
- } else {
- /* Otherwise start normal probing */
- start_generic_probing (task, MM_AT_SERIAL_PORT (port));
- }
-}
-
-static gboolean
-try_open (gpointer user_data)
-{
- MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data);
- MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
- GError *error = NULL;
-
- task_priv->open_id = 0;
-
- if (!mm_serial_port_open (MM_SERIAL_PORT (task_priv->probe_port), &error)) {
- if (++task_priv->open_tries > 4) {
- /* took too long to open the port; give up */
- g_warning ("(%s): failed to open after 4 tries.",
- mm_port_get_device (MM_PORT (task_priv->probe_port)));
- probe_complete (task);
- } else if (g_error_matches (error,
- MM_SERIAL_ERROR,
- MM_SERIAL_ERROR_OPEN_FAILED_NO_DEVICE)) {
- /* this is nozomi being dumb; try again */
- task_priv->open_id = g_timeout_add_seconds (1, try_open, task);
- } else {
- /* some other hard error */
- probe_complete (task);
- }
- g_clear_error (&error);
- } else {
- /* success, start probing */
- GUdevDevice *port;
-
- port = mm_plugin_base_supports_task_get_port (task);
- g_assert (port);
-
- task_priv->full_id = g_signal_connect (task_priv->probe_port, "buffer-full",
- G_CALLBACK (port_buffer_full), task);
-
- mm_dbg ("(%s): probe requested by plugin '%s'",
- g_udev_device_get_name (port),
- mm_plugin_get_name (MM_PLUGIN (task_priv->plugin)));
- mm_serial_port_flash (MM_SERIAL_PORT (task_priv->probe_port), 100, TRUE, flash_done, task);
- }
-
- return FALSE;
-}
-
-gboolean
-mm_plugin_base_probe_port (MMPluginBase *self,
- MMPluginBaseSupportsTask *task,
- guint64 send_delay_us,
- GError **error)
-{
- MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
- MMAtSerialPort *serial;
- const char *name;
- GUdevDevice *port;
-
- g_return_val_if_fail (self != NULL, FALSE);
- g_return_val_if_fail (MM_IS_PLUGIN_BASE (self), FALSE);
- g_return_val_if_fail (task != NULL, FALSE);
-
- port = mm_plugin_base_supports_task_get_port (task);
- g_assert (port);
- name = g_udev_device_get_name (port);
- g_assert (name);
-
- serial = mm_at_serial_port_new (name);
- if (serial == NULL) {
- g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Failed to create new serial port.");
- return FALSE;
- }
-
- g_object_set (serial,
- MM_SERIAL_PORT_SEND_DELAY, send_delay_us,
- MM_PORT_CARRIER_DETECT, FALSE,
- MM_SERIAL_PORT_SPEW_CONTROL, TRUE,
- NULL);
-
- mm_at_serial_port_set_response_parser (serial,
- mm_serial_parser_v1_parse,
- mm_serial_parser_v1_new (),
- mm_serial_parser_v1_destroy);
-
- /* Open the port */
- task_priv->probe_port = serial;
- task_priv->cur_custom = task_priv->custom;
- task_priv->open_id = g_idle_add (try_open, task);
- return TRUE;
-}
-
-gboolean
-mm_plugin_base_get_cached_probe_result (MMPluginBase *self,
- GUdevDevice *port,
- guint32 *capabilities,
- gchar **vendor,
- gchar **product)
-{
- MMPluginBaseProbedInfo *info;
-
- if (g_hash_table_lookup_extended (probed_info,
- g_udev_device_get_name (port),
- NULL,
- (gpointer *)&info)) {
- if (capabilities)
- *capabilities = info->capabilities;
- if (vendor)
- *vendor = (info->vendor ? g_strdup (info->vendor) : NULL);
- if (product)
- *product = (info->product ? g_strdup (info->product) : NULL);
- return TRUE;
- }
-
- if (capabilities)
- *capabilities = 0;
- if (vendor)
- *vendor = NULL;
- if (product)
- *product = NULL;
- return FALSE;
-}
-
/*****************************************************************************/
-static void
-modem_destroyed (gpointer data, GObject *modem)
-{
- /* Since we don't track port cached capabilities on a per-modem basis,
- * we just have to live with blowing away the cached capabilities whenever
- * a modem gets removed. Could do better here by storing a structure
- * in the cached capabilities table that includes { caps, modem device }
- * or something and then only removing cached capabilities for ports
- * that the modem that was just removed owned, but whatever.
- */
- g_hash_table_remove_all (probed_info);
-}
-
gboolean
mm_plugin_base_get_device_ids (MMPluginBase *self,
const char *subsys,
@@ -1314,7 +238,7 @@ get_driver_name (GUdevDevice *device)
}
static gboolean
-device_file_exists(const char *name)
+device_file_exists (const char *name)
{
char *devfile;
struct stat s;
@@ -1327,22 +251,46 @@ device_file_exists(const char *name)
return (0 == result) ? TRUE : FALSE;
}
-static SupportsPortResult *
-supports_port_result_new (MMPluginSupportsResult result,
- guint support_level)
+static gboolean
+is_virtual_port (const gchar *device_name)
{
- SupportsPortResult *spr;
+ guint idx;
+
+ /* Detect any modems accessible through the list of virtual ports */
+ for (idx = 0; virtual_port[idx]; idx++) {
+ if (strcmp (device_name, virtual_port[idx]))
+ continue;
+ if (!device_file_exists (virtual_port[idx]))
+ continue;
+
+ return TRUE;
+ }
- spr = g_malloc (sizeof (SupportsPortResult));
- spr->result = result;
- spr->support_level = support_level;
- return spr;
+ return FALSE;
}
static void
-supports_port_result_free (SupportsPortResult *spr)
+port_probe_run_ready (MMPortProbe *probe,
+ GAsyncResult *probe_result,
+ GSimpleAsyncResult *supports_port_result)
{
- g_free (spr);
+ GError *error = NULL;
+
+ if (!mm_port_probe_run_finish (probe, probe_result, &error)) {
+ /* Probing failed */
+ g_simple_async_result_take_error (supports_port_result, error);
+ } else {
+ /* Probing succeeded */
+ guint32 capabilities;
+
+ /* TODO: Let plugins decide which capabilities they support */
+ capabilities = mm_port_probe_get_capabilities (probe);
+ g_simple_async_result_set_op_res_gboolean (supports_port_result,
+ (capabilities > 0 ? TRUE : FALSE));
+ }
+
+ /* Complete the async supports port request */
+ g_simple_async_result_complete_in_idle (supports_port_result);
}
static MMPluginSupportsResult
@@ -1351,8 +299,6 @@ supports_port_finish (MMPlugin *self,
guint *level,
GError **error)
{
- SupportsPortResult *spr;
-
g_return_val_if_fail (MM_IS_PLUGIN (self),
MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED);
g_return_val_if_fail (G_IS_ASYNC_RESULT (result),
@@ -1361,12 +307,15 @@ supports_port_finish (MMPlugin *self,
/* Propagate error, if any */
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
error)) {
- return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ }
+
+ if (g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result))) {
+ *level = 10; /* dummy */
+ return MM_PLUGIN_SUPPORTS_PORT_SUPPORTED;
}
- spr = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
- *level = spr->support_level;
- return spr->result;
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
static void
@@ -1378,14 +327,12 @@ supports_port (MMPlugin *plugin,
GAsyncReadyCallback callback,
gpointer user_data)
{
- MMPluginSupportsResult result = MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
MMPluginBase *self = MM_PLUGIN_BASE (plugin);
MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
GUdevDevice *port = NULL;
gchar *driver = NULL;
gchar *key = NULL;
- MMPluginBaseSupportsTask *task;
- gint idx;
+ MMPortProbe *probe;
GSimpleAsyncResult *async_result;
async_result = g_simple_async_result_new (G_OBJECT (self),
@@ -1393,75 +340,59 @@ supports_port (MMPlugin *plugin,
user_data,
supports_port);
- /* Lookup task, there shouldn't be any */
+ /* Lookup current probes, there shouldn't be any */
key = get_key (subsys, name);
- task = g_hash_table_lookup (priv->tasks, key);
- if (task) {
+ probe = g_hash_table_lookup (priv->tasks, key);
+ if (probe) {
g_warn_if_reached ();
- goto unsupported;
+ goto out;
}
/* Get port device */
- port = g_udev_client_query_by_subsystem_and_name (priv->client,
- subsys,
- name);
- if (!port)
- goto unsupported;
+ if (!(port = g_udev_client_query_by_subsystem_and_name (priv->client,
+ subsys,
+ name))) {
+ g_simple_async_result_set_error (async_result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID,
+ "Couldn't find port for (%s/%s)",
+ subsys,
+ name);
+ g_simple_async_result_complete_in_idle (async_result);
+ goto out;
+ }
/* Detect any modems accessible through the list of virtual ports */
- for (idx = 0; virtual_port[idx]; idx++) {
- if (strcmp(name, virtual_port[idx]))
- continue;
- if (!device_file_exists(virtual_port[idx]))
- continue;
-
- task = supports_task_new (self,
- port,
- physdev_path,
- "virtual",
- async_result);
- goto find_plugin;
+ if (!(driver = (is_virtual_port (name) ?
+ g_strdup ("virtual") :
+ get_driver_name (port)))) {
+ g_simple_async_result_set_error (async_result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID,
+ "Couldn't find driver for (%s/%s)",
+ subsys,
+ name);
+ g_simple_async_result_complete_in_idle (async_result);
+ goto out;
}
- driver = get_driver_name (port);
- if (!driver)
- goto unsupported;
+ /* Need to launch new probing */
+ probe = mm_port_probe_cache_get (port, physdev_path, driver);
+ g_assert (probe);
- /* Create new supports task for this port */
- task = supports_task_new (self,
- port,
- physdev_path,
- driver,
- async_result);
+ /* Launch the probe */
+ mm_dbg ("(%s) launching probe for (%s,%s)!", priv->name, subsys, name);
+ mm_port_probe_run (probe,
+ MM_PORT_PROBE_AT_CAPABILITIES,
+ priv->send_delay,
+ priv->custom_init,
+ (GAsyncReadyCallback)port_probe_run_ready,
+ g_object_ref (async_result));
-find_plugin:
- /* Keep track of the task */
+ /* Keep track of the probe */
g_hash_table_insert (priv->tasks,
g_strdup (key),
- g_object_ref (task));
-
- /* Let the specific plugin check port support */
- result = MM_PLUGIN_BASE_GET_CLASS (self)->supports_port (self,
- existing,
- task);
- if (result == MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS) {
- /* It will really be asynchronous */
- goto out;
- }
-
- /* If the plugin doesn't support the port at all, the supports task is
- * not needed.
- */
- g_hash_table_remove (priv->tasks, key);
- g_object_unref (task);
-
-unsupported:
- /* Set the result of the asynchronous method just here */
- g_simple_async_result_set_op_res_gpointer (
- async_result,
- supports_port_result_new (result, 0),
- (GDestroyNotify)supports_port_result_free);
- g_simple_async_result_complete_in_idle (async_result);
+ g_object_ref (probe));
out:
if (port)
@@ -1478,15 +409,13 @@ supports_port_cancel (MMPlugin *plugin,
{
MMPluginBase *self = MM_PLUGIN_BASE (plugin);
MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
- MMPluginBaseSupportsTask *task;
- char *key;
+ MMPortProbe *probe;
+ gchar *key;
key = get_key (subsys, name);
- task = g_hash_table_lookup (priv->tasks, key);
- if (task) {
- /* Let the plugin cancel any ongoing tasks */
- if (MM_PLUGIN_BASE_GET_CLASS (self)->cancel_task)
- MM_PLUGIN_BASE_GET_CLASS (self)->cancel_task (self, task);
+ probe = g_hash_table_lookup (priv->tasks, key);
+ if (probe) {
+ mm_port_probe_run_cancel (probe);
g_hash_table_remove (priv->tasks, key);
}
@@ -1502,21 +431,19 @@ grab_port (MMPlugin *plugin,
{
MMPluginBase *self = MM_PLUGIN_BASE (plugin);
MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
- MMPluginBaseSupportsTask *task;
+ MMPortProbe *probe;
MMModem *modem = NULL;
char *key;
key = get_key (subsys, name);
- task = g_hash_table_lookup (priv->tasks, key);
- if (!task) {
- g_free (key);
- g_return_val_if_fail (task != NULL, FALSE);
- }
+ probe = g_hash_table_lookup (priv->tasks, key);
+ g_assert (probe);
/* Let the modem grab the port */
- modem = MM_PLUGIN_BASE_GET_CLASS (self)->grab_port (self, existing, task, error);
- if (modem && !existing)
- g_object_weak_ref (G_OBJECT (modem), modem_destroyed, self);
+ modem = MM_PLUGIN_BASE_GET_CLASS (self)->grab_port (self,
+ existing,
+ probe,
+ error);
g_hash_table_remove (priv->tasks, key);
g_free (key);
@@ -1543,13 +470,6 @@ mm_plugin_base_init (MMPluginBase *self)
MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
const char *subsys[] = { "tty", "net", NULL };
- if (!probed_info) {
- probed_info = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- (GDestroyNotify) probed_info_free);
- }
-
priv->client = g_udev_client_new (subsys);
priv->tasks = g_hash_table_new_full (g_str_hash,
@@ -1698,8 +618,6 @@ mm_plugin_base_class_init (MMPluginBaseClass *klass)
g_type_class_add_private (object_class, sizeof (MMPluginBasePrivate));
- klass->handle_probe_response = real_handle_probe_response;
-
/* Virtual methods */
object_class->get_property = get_property;
object_class->set_property = set_property;
@@ -1812,13 +730,4 @@ mm_plugin_base_class_init (MMPluginBaseClass *klass)
"list of plugins loaded",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
- signals[PROBE_RESULT] =
- g_signal_new ("probe-result",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (MMPluginBaseClass, probe_result),
- NULL, NULL,
- mm_marshal_VOID__OBJECT_UINT,
- G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_UINT);
}
diff --git a/src/mm-plugin-base.h b/src/mm-plugin-base.h
index 82adb643..5ab0df02 100644
--- a/src/mm-plugin-base.h
+++ b/src/mm-plugin-base.h
@@ -25,85 +25,7 @@
#include "mm-plugin.h"
#include "mm-modem.h"
#include "mm-port.h"
-
-#define MM_PLUGIN_BASE_PORT_CAP_GSM 0x0001 /* GSM */
-#define MM_PLUGIN_BASE_PORT_CAP_IS707_A 0x0002 /* CDMA Circuit Switched Data */
-#define MM_PLUGIN_BASE_PORT_CAP_IS707_P 0x0004 /* CDMA Packet Switched Data */
-#define MM_PLUGIN_BASE_PORT_CAP_DS 0x0008 /* Data compression selection (v.42bis) */
-#define MM_PLUGIN_BASE_PORT_CAP_ES 0x0010 /* Error control selection (v.42) */
-#define MM_PLUGIN_BASE_PORT_CAP_FCLASS 0x0020 /* Group III Fax */
-#define MM_PLUGIN_BASE_PORT_CAP_MS 0x0040 /* Modulation selection */
-#define MM_PLUGIN_BASE_PORT_CAP_W 0x0080 /* Wireless commands */
-#define MM_PLUGIN_BASE_PORT_CAP_IS856 0x0100 /* CDMA 3G EVDO rev 0 */
-#define MM_PLUGIN_BASE_PORT_CAP_IS856_A 0x0200 /* CDMA 3G EVDO rev A */
-#define MM_PLUGIN_BASE_PORT_CAP_QCDM 0x0400 /* QCDM-capable port */
-#define MM_PLUGIN_BASE_PORT_CAP_AT 0x0800 /* Responds to AT commands */
-#define MM_PLUGIN_BASE_PORT_CAP_IRIDIUM 0x1000 /* Iridium */
-
-#define MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK (mm_plugin_base_supports_task_get_type ())
-#define MM_PLUGIN_BASE_SUPPORTS_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK, MMPluginBaseSupportsTask))
-#define MM_PLUGIN_BASE_SUPPORTS_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK, MMPluginBaseSupportsTaskClass))
-#define MM_IS_PLUGIN_BASE_SUPPORTS_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK))
-#define MM_IS_PLUBIN_BASE_SUPPORTS_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK))
-#define MM_PLUGIN_BASE_SUPPORTS_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_BASE_SUPPORTS_TASK, MMPluginBaseSupportsTaskClass))
-
-typedef struct {
- GObject parent;
-} MMPluginBaseSupportsTask;
-
-typedef struct {
- GObjectClass parent;
-} MMPluginBaseSupportsTaskClass;
-
-GType mm_plugin_base_supports_task_get_type (void);
-
-/*
- * response: the response string from the modem, if no error occurred
- * error: the error returned by the modem or serial stack, if any
- * tries: number of times the custom init command has been sent to the modem
- * out_stop: on return, TRUE means stop the probe and close the port
- * out_level: on return, if out_stop is TRUE this should indicate the plugin's
- * support level for this modem
- *
- * Function should return TRUE if the custom init command should be retried,
- * FALSE if it should not. If FALSE is returned, generic probing will continue
- * if out_stop == FALSE.
- */
-typedef gboolean (*MMBaseSupportsTaskCustomInitResultFunc) (MMPluginBaseSupportsTask *task,
- GString *response,
- GError *error,
- guint32 tries,
- gboolean *out_stop,
- guint32 *out_level,
- gpointer user_data);
-
-MMPlugin *mm_plugin_base_supports_task_get_plugin (MMPluginBaseSupportsTask *task);
-
-GUdevDevice *mm_plugin_base_supports_task_get_port (MMPluginBaseSupportsTask *task);
-
-const char *mm_plugin_base_supports_task_get_physdev_path (MMPluginBaseSupportsTask *task);
-
-const char *mm_plugin_base_supports_task_get_driver (MMPluginBaseSupportsTask *task);
-
-guint32 mm_plugin_base_supports_task_get_probed_capabilities (MMPluginBaseSupportsTask *task);
-
-MMPortType mm_plugin_base_probed_capabilities_to_port_type (guint32 caps);
-
-const gchar *mm_plugin_base_supports_task_get_probed_vendor (MMPluginBaseSupportsTask *task);
-
-const gchar *mm_plugin_base_supports_task_get_probed_product (MMPluginBaseSupportsTask *task);
-
-gboolean mm_plugin_base_supports_task_propagate_cached (MMPluginBaseSupportsTask *task);
-
-
-void mm_plugin_base_supports_task_complete (MMPluginBaseSupportsTask *task,
- guint32 level);
-
-void mm_plugin_base_supports_task_add_custom_init_command (MMPluginBaseSupportsTask *task,
- const char *cmd,
- guint32 delay_seconds,
- MMBaseSupportsTaskCustomInitResultFunc callback,
- gpointer callback_data);
+#include "mm-port-probe.h"
#define MM_TYPE_PLUGIN_BASE (mm_plugin_base_get_type ())
#define MM_PLUGIN_BASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_BASE, MMPluginBase))
@@ -112,17 +34,6 @@ void mm_plugin_base_supports_task_add_custom_init_command (MMPluginBaseSupportsT
#define MM_IS_PLUBIN_BASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_BASE))
#define MM_PLUGIN_BASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_BASE, MMPluginBaseClass))
-/* Structure defining custom commands that the plugins may need to initialize
- * the devices */
-typedef struct {
- /* AT command to send to the modem */
- gchar *command;
- /* Number of allowed retries (>= 0) */
- guint retries;
- /* Callback to call when reply received */
- MMBaseSupportsTaskCustomInitResultFunc callback;
-} MMPluginCustomInit;
-
#define MM_PLUGIN_BASE_NAME "name"
#define MM_PLUGIN_BASE_ALLOWED_CAPABILITIES "allowed-capabilities"
#define MM_PLUGIN_BASE_ALLOWED_SUBSYSTEMS "allowed-subsystems"
@@ -148,30 +59,10 @@ struct _MMPluginBaseClass {
GObjectClass parent;
/* Mandatory subclass functions */
- MMPluginSupportsResult (*supports_port) (MMPluginBase *plugin,
- MMModem *existing,
- MMPluginBaseSupportsTask *task);
-
MMModem *(*grab_port) (MMPluginBase *plugin,
MMModem *existing,
- MMPluginBaseSupportsTask *task,
+ MMPortProbe *probe,
GError **error);
-
- /* Optional subclass functions */
- void (*cancel_task) (MMPluginBase *plugin,
- MMPluginBaseSupportsTask *task);
-
- /* Lets plugins read the probe response before the generic plugin processes it */
- void (*handle_probe_response) (MMPluginBase *plugin,
- MMPluginBaseSupportsTask *task,
- const char *command,
- const char *response,
- const GError *error);
-
- /* Signals */
- void (*probe_result) (MMPluginBase *self,
- MMPluginBaseSupportsTask *task,
- guint32 capabilities);
};
GType mm_plugin_base_get_type (void);
@@ -182,17 +73,5 @@ gboolean mm_plugin_base_get_device_ids (MMPluginBase *self,
guint16 *vendor,
guint16 *product);
-gboolean mm_plugin_base_probe_port (MMPluginBase *self,
- MMPluginBaseSupportsTask *task,
- guint64 send_delay_us,
- GError **error);
-
-/* Returns TRUE if the port was previously probed, FALSE if not */
-gboolean mm_plugin_base_get_cached_probe_result (MMPluginBase *self,
- GUdevDevice *port,
- guint32 *capabilities,
- gchar **vendor,
- gchar **product);
-
#endif /* MM_PLUGIN_BASE_H */