diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2011-09-10 16:20:11 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-15 14:14:20 +0100 |
commit | 610bffc4e817fa04dcde19d31584b194038fdde6 (patch) | |
tree | ceecda3d8425173f5de4d1406e1128cee0e9702f | |
parent | b73fb8e8f27ac34ec5aa16e3e5a3605b03dbe740 (diff) |
port-probe: enable probing for QCDM support
-rw-r--r-- | src/mm-port-probe.c | 167 | ||||
-rw-r--r-- | src/mm-port-probe.h | 2 |
2 files changed, 168 insertions, 1 deletions
diff --git a/src/mm-port-probe.c b/src/mm-port-probe.c index 7fa28ab1..ec425f64 100644 --- a/src/mm-port-probe.c +++ b/src/mm-port-probe.c @@ -26,6 +26,10 @@ #include "mm-serial-port.h" #include "mm-serial-parsers.h" #include "mm-port-probe-at-command.h" +#include "libqcdm/src/commands.h" +#include "libqcdm/src/utils.h" +#include "libqcdm/src/errors.h" +#include "mm-qcdm-serial-port.h" G_DEFINE_TYPE (MMPortProbe, mm_port_probe, G_TYPE_OBJECT) @@ -60,6 +64,7 @@ struct _MMPortProbePrivate { /* Probing results */ guint32 flags; gboolean is_at; + gboolean is_qcdm; guint32 capabilities; gchar *vendor; gchar *product; @@ -69,6 +74,7 @@ struct _MMPortProbePrivate { }; static gboolean serial_probe_at (MMPortProbe *self); +static gboolean serial_probe_qcdm (MMPortProbe *self); static void serial_probe_schedule (MMPortProbe *self); static void @@ -143,6 +149,139 @@ port_probe_run_is_cancelled (MMPortProbe *self) } static void +serial_probe_qcdm_parse_response (MMQcdmSerialPort *port, + GByteArray *response, + GError *error, + MMPortProbe *self) +{ + QcdmResult *result; + gint err = QCDM_SUCCESS; + + /* 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 */ + qcdm_result_unref (result); + self->priv->is_qcdm = TRUE; + + /* Also set as not an AT port */ + self->priv->is_at = FALSE; + self->priv->flags |= MM_PORT_PROBE_AT; + } + } + + /* Mark as being probed */ + self->priv->flags |= MM_PORT_PROBE_QCDM; + + /* Reschedule probing */ + serial_probe_schedule (self); +} + +static gboolean +serial_probe_qcdm (MMPortProbe *self) +{ + PortProbeRunTask *task = self->priv->task; + GError *error = NULL; + GByteArray *verinfo = NULL; + GByteArray *verinfo2; + gint len; + + task->source_id = 0; + + /* If already cancelled, do nothing else */ + if (port_probe_run_is_cancelled (self)) + return FALSE; + + mm_dbg ("(%s) probing QCDM...", self->priv->name); + + /* If open, close the AT port */ + if (task->serial) { + mm_serial_port_close (task->serial); + g_object_unref (task->serial); + } + + /* Open the QCDM port */ + task->serial = MM_SERIAL_PORT (mm_qcdm_serial_port_new (self->priv->name, + MM_PORT_TYPE_PRIMARY)); + if (!task->serial) { + port_probe_run_task_complete ( + task, + FALSE, + FALSE, + g_error_new (MM_CORE_ERROR, + MM_CORE_ERROR_INVALID, + "(%s) Couldn't create QCDM port", + self->priv->name)); + return FALSE; + } + + /* Try to open the port */ + if (!mm_serial_port_open (task->serial, &error)) { + port_probe_run_task_complete ( + task, + FALSE, + FALSE, + g_error_new (MM_SERIAL_ERROR, + MM_SERIAL_ERROR_OPEN_FAILED, + "(%s) Failed to open QCDM port: %s", + self->priv->name, + (error ? error->message : "unknown error"))); + g_clear_error (&error); + return FALSE; + } + + /* Build up the probe command */ + verinfo = g_byte_array_sized_new (50); + len = qcdm_cmd_version_info_new ((gchar *) verinfo->data, 50); + if (len <= 0) { + g_byte_array_free (verinfo, TRUE); + port_probe_run_task_complete ( + task, + FALSE, + FALSE, + g_error_new (MM_SERIAL_ERROR, + MM_SERIAL_ERROR_OPEN_FAILED, + "(%s) Failed to create QCDM versin info command", + self->priv->name)); + return FALSE; + } + verinfo->len = len; + + /* Queuing the command takes ownership over it; dup it for the second try */ + verinfo2 = g_byte_array_sized_new (verinfo->len); + g_byte_array_append (verinfo2, verinfo->data, verinfo->len); + + /* Send the command twice; the ports often need to be woken up */ + mm_qcdm_serial_port_queue_command (MM_QCDM_SERIAL_PORT (task->serial), + verinfo, + 3, + (MMQcdmSerialResponseFn)serial_probe_qcdm_parse_response, + NULL); + mm_qcdm_serial_port_queue_command (MM_QCDM_SERIAL_PORT (task->serial), + verinfo2, + 3, + (MMQcdmSerialResponseFn)serial_probe_qcdm_parse_response, + self); + + return FALSE; +} + +static void serial_probe_at_product_result_processor (MMPortProbe *self, GValue *result) { @@ -211,6 +350,10 @@ serial_probe_at_result_processor (MMPortProbe *self, mm_dbg ("(%s) port is AT-capable", self->priv->name); self->priv->is_at = TRUE; self->priv->flags |= MM_PORT_PROBE_AT; + + /* Also set as not a QCDM port */ + self->priv->is_qcdm = FALSE; + self->priv->flags |= MM_PORT_PROBE_QCDM; return; } } @@ -348,6 +491,13 @@ serial_probe_schedule (MMPortProbe *self) return; } + /* QCDM requested and not already probed? */ + if ((task->flags & MM_PORT_PROBE_QCDM) && + !(self->priv->flags & MM_PORT_PROBE_QCDM)) { + task->source_id = g_idle_add ((GSourceFunc)serial_probe_qcdm, self); + return; + } + /* All done! Finish asynchronously */ port_probe_run_task_complete (task, TRUE, TRUE, NULL); } @@ -575,7 +725,7 @@ mm_port_probe_run (MMPortProbe *self, /* Check if we already have the requested probing results. * We will fix here the 'task->flags' so that we only request probing * for the missing things. */ - for (i = MM_PORT_PROBE_AT; i <= MM_PORT_PROBE_AT_PRODUCT; i = (i << 1)) { + for (i = MM_PORT_PROBE_AT; i <= MM_PORT_PROBE_QCDM; i = (i << 1)) { if ((flags & i) && !(self->priv->flags & i)) { task->flags += i; } @@ -609,6 +759,12 @@ mm_port_probe_run (MMPortProbe *self, return; } + /* Otherwise, start by opening as QCDM port */ + if (task->flags & MM_PORT_PROBE_QCDM) { + task->source_id = g_idle_add ((GSourceFunc)serial_probe_qcdm, self); + return; + } + /* Shouldn't happen */ g_assert_not_reached (); } @@ -622,6 +778,15 @@ mm_port_probe_is_at (MMPortProbe *self) return self->priv->is_at; } +gboolean +mm_port_probe_is_qcdm (MMPortProbe *self) +{ + g_return_val_if_fail (MM_IS_PORT_PROBE (self), FALSE); + g_return_val_if_fail (self->priv->flags & MM_PORT_PROBE_QCDM, FALSE); + + return self->priv->is_qcdm; +} + guint32 mm_port_probe_get_capabilities (MMPortProbe *self) { diff --git a/src/mm-port-probe.h b/src/mm-port-probe.h index 4616fe66..0b14c34b 100644 --- a/src/mm-port-probe.h +++ b/src/mm-port-probe.h @@ -35,6 +35,7 @@ #define MM_PORT_PROBE_AT_CAPABILITIES 0x0002 #define MM_PORT_PROBE_AT_VENDOR 0x0004 #define MM_PORT_PROBE_AT_PRODUCT 0x0008 +#define MM_PORT_PROBE_QCDM 0x0010 /* Flags to report probed capabilities */ #define MM_PORT_PROBE_CAPABILITY_GSM 0x0001 /* GSM */ @@ -96,6 +97,7 @@ gboolean mm_port_probe_run_cancel (MMPortProbe *self); /* Probing result getters */ gboolean mm_port_probe_is_at (MMPortProbe *self); +gboolean mm_port_probe_is_qcdm (MMPortProbe *self); guint32 mm_port_probe_get_capabilities (MMPortProbe *self); const gchar *mm_port_probe_get_vendor (MMPortProbe *self); const gchar *mm_port_probe_get_product (MMPortProbe *self); |