diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-port-probe-at-command.c | 121 | ||||
-rw-r--r-- | src/mm-port-probe-at-command.h | 1 | ||||
-rw-r--r-- | src/mm-port-probe.c | 52 | ||||
-rw-r--r-- | src/mm-port-probe.h | 28 |
4 files changed, 196 insertions, 6 deletions
diff --git a/src/mm-port-probe-at-command.c b/src/mm-port-probe-at-command.c index 840cc4e3..72a49f1b 100644 --- a/src/mm-port-probe-at-command.c +++ b/src/mm-port-probe-at-command.c @@ -15,6 +15,9 @@ * Copyright (C) 2011 Aleksander Morgado <aleksander@gnu.org> */ +#define _GNU_SOURCE /* for strcasestr */ +#include <string.h> + #include <glib.h> #include "mm-errors.h" @@ -69,3 +72,121 @@ mm_port_probe_at_command_get_probing (void) { return at_probing; } + +/* ---- CAPABILITIES probing ---- */ + +struct modem_caps { + gchar *name; + guint32 bits; +}; + +static const struct modem_caps modem_caps[] = { + { "+CGSM", MM_PORT_PROBE_CAPABILITY_GSM }, + { "+CIS707-A", MM_PORT_PROBE_CAPABILITY_IS707_A }, + { "+CIS707A", MM_PORT_PROBE_CAPABILITY_IS707_A }, /* Cmotech */ + { "+CIS707", MM_PORT_PROBE_CAPABILITY_IS707_A }, + { "CIS707", MM_PORT_PROBE_CAPABILITY_IS707_A }, /* Qualcomm Gobi */ + { "+CIS707P", MM_PORT_PROBE_CAPABILITY_IS707_P }, + { "CIS-856", MM_PORT_PROBE_CAPABILITY_IS856 }, + { "+IS-856", MM_PORT_PROBE_CAPABILITY_IS856 }, /* Cmotech */ + { "CIS-856-A", MM_PORT_PROBE_CAPABILITY_IS856_A }, + { "CIS-856A", MM_PORT_PROBE_CAPABILITY_IS856_A }, /* Kyocera KPC680 */ + { "+DS", MM_PORT_PROBE_CAPABILITY_DS }, + { "+ES", MM_PORT_PROBE_CAPABILITY_ES }, + { "+MS", MM_PORT_PROBE_CAPABILITY_MS }, + { "+FCLASS", MM_PORT_PROBE_CAPABILITY_FCLASS }, + { NULL } +}; + +static gboolean +parse_caps_gcap (const gchar *response, + const GError *error, + GValue *result, + GError **result_error) +{ + const struct modem_caps *cap = modem_caps; + guint32 ret = 0; + + /* 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:")) + return FALSE; + + while (cap->name) { + if (strstr (response, cap->name)) + ret |= cap->bits; + cap++; + } + + /* No result built? */ + if (ret == 0) + return FALSE; + + g_value_init (result, G_TYPE_UINT); + g_value_set_uint (result, (guint)ret); + return TRUE; +} + +static gboolean +parse_caps_cpin (const gchar *response, + const GError *error, + GValue *result, + GError **result_error) +{ + if (strcasestr (response, "SIM PIN") || + strcasestr (response, "SIM PUK") || + strcasestr (response, "PH-SIM PIN") || + strcasestr (response, "PH-FSIM PIN") || + strcasestr (response, "PH-FSIM PUK") || + strcasestr (response, "SIM PIN2") || + strcasestr (response, "SIM PUK2") || + strcasestr (response, "PH-NET PIN") || + strcasestr (response, "PH-NET PUK") || + strcasestr (response, "PH-NETSUB PIN") || + strcasestr (response, "PH-NETSUB PUK") || + strcasestr (response, "PH-SP PIN") || + strcasestr (response, "PH-SP PUK") || + strcasestr (response, "PH-CORP PIN") || + strcasestr (response, "PH-CORP PUK") || + strcasestr (response, "READY")) { + /* At least, it's a GSM modem */ + g_value_init (result, G_TYPE_UINT); + g_value_set_uint (result, MM_PORT_PROBE_CAPABILITY_GSM); + return TRUE; + } + return FALSE; +} + +static gboolean +parse_caps_cgmm (const gchar *response, + const GError *error, + GValue *result, + GError **result_error) +{ + if (strstr (response, "GSM900") || + strstr (response, "GSM1800") || + strstr (response, "GSM1900") || + strstr (response, "GSM850")) { + /* At least, it's a GSM modem */ + g_value_init (result, G_TYPE_UINT); + g_value_set_uint (result, MM_PORT_PROBE_CAPABILITY_GSM); + return TRUE; + } + return FALSE; +} + +static const MMPortProbeAtCommand capabilities_probing[] = { + { "+GCAP", parse_caps_gcap }, + { "I", parse_caps_gcap }, + { "+CPIN?", parse_caps_cpin }, + { "+CGMM", parse_caps_cgmm }, + { NULL } +}; + +const MMPortProbeAtCommand * +mm_port_probe_at_command_get_capabilities_probing (void) +{ + return capabilities_probing; +} + diff --git a/src/mm-port-probe-at-command.h b/src/mm-port-probe-at-command.h index 60ccd8e0..d66b2084 100644 --- a/src/mm-port-probe-at-command.h +++ b/src/mm-port-probe-at-command.h @@ -52,6 +52,7 @@ typedef struct { /* Default commands used during probing */ const MMPortProbeAtCommand *mm_port_probe_at_command_get_probing (void); +const MMPortProbeAtCommand *mm_port_probe_at_command_get_capabilities_probing (void); #endif /* MM_PORT_PROBE_AT_COMMAND_H */ diff --git a/src/mm-port-probe.c b/src/mm-port-probe.c index 685fd5a4..1332be0b 100644 --- a/src/mm-port-probe.c +++ b/src/mm-port-probe.c @@ -60,6 +60,7 @@ struct _MMPortProbePrivate { /* Probing results */ guint32 flags; gboolean is_at; + guint32 capabilities; /* Current probing task. Only one can be available at a time */ PortProbeRunTask *task; @@ -140,6 +141,25 @@ port_probe_run_is_cancelled (MMPortProbe *self) } static void +serial_probe_at_capabilities_result_processor (MMPortProbe *self, + GValue *result) +{ + if (result) { + /* If any result given, it must be a uint */ + g_assert (G_VALUE_HOLDS_UINT (result)); + + mm_dbg ("(%s) capabilities probing finished", self->priv->name); + self->priv->capabilities = (guint32) g_value_get_uint (result); + self->priv->flags |= MM_PORT_PROBE_AT_CAPABILITIES; + return; + } + + mm_dbg ("(%s) no result in capabilities probing", self->priv->name); + self->priv->capabilities = 0; + self->priv->flags |= MM_PORT_PROBE_AT_CAPABILITIES; +} + +static void serial_probe_at_result_processor (MMPortProbe *self, GValue *result) { @@ -157,7 +177,8 @@ serial_probe_at_result_processor (MMPortProbe *self, mm_dbg ("(%s) port is not AT-capable", self->priv->name); self->priv->is_at = FALSE; - self->priv->flags |= MM_PORT_PROBE_AT; + self->priv->flags |= (MM_PORT_PROBE_AT | + MM_PORT_PROBE_AT_CAPABILITIES); } static void @@ -256,6 +277,13 @@ serial_probe_schedule (MMPortProbe *self) task->at_result_processor = serial_probe_at_result_processor; task->at_commands = mm_port_probe_at_command_get_probing (); } + /* Capabilities requested and not already probed? */ + else if ((task->flags & MM_PORT_PROBE_AT_CAPABILITIES) && + !(self->priv->flags & MM_PORT_PROBE_AT_CAPABILITIES)) { + /* Prepare AT capabilities probing */ + task->at_result_processor = serial_probe_at_capabilities_result_processor; + task->at_commands = mm_port_probe_at_command_get_capabilities_probing (); + } /* If a next AT group detected, go for it */ if (task->at_result_processor && @@ -471,6 +499,7 @@ mm_port_probe_run (MMPortProbe *self, gpointer user_data) { PortProbeRunTask *task; + guint32 i; g_return_if_fail (MM_IS_PORT_PROBE (self)); g_return_if_fail (flags != 0); @@ -490,9 +519,10 @@ 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. */ - if ((flags & MM_PORT_PROBE_AT) && - !(self->priv->flags & MM_PORT_PROBE_AT)) { - task->flags += MM_PORT_PROBE_AT; + for (i = MM_PORT_PROBE_AT; i <= MM_PORT_PROBE_AT_CAPABILITIES; i = (i << 1)) { + if ((flags & i) && !(self->priv->flags & i)) { + task->flags += i; + } } /* All requested probings already available? If so, we're done */ @@ -510,6 +540,11 @@ mm_port_probe_run (MMPortProbe *self, /* Store as current task */ self->priv->task = task; + /* If any AT-specific probing requested, require generic AT check before */ + if (task->flags & MM_PORT_PROBE_AT_CAPABILITIES) { + task->flags |= MM_PORT_PROBE_AT; + } + /* If any AT probing is needed, start by opening as AT port */ if (task->flags & MM_PORT_PROBE_AT) { task->source_id = g_idle_add ((GSourceFunc)serial_open_at, self); @@ -529,6 +564,15 @@ mm_port_probe_is_at (MMPortProbe *self) return self->priv->is_at; } +guint32 +mm_port_probe_get_capabilities (MMPortProbe *self) +{ + g_return_val_if_fail (MM_IS_PORT_PROBE (self), 0); + g_return_val_if_fail (self->priv->flags & MM_PORT_PROBE_AT_CAPABILITIES, 0); + + return self->priv->capabilities; +} + GUdevDevice * mm_port_probe_get_port (MMPortProbe *self) { diff --git a/src/mm-port-probe.h b/src/mm-port-probe.h index 127f2263..46b03bc6 100644 --- a/src/mm-port-probe.h +++ b/src/mm-port-probe.h @@ -31,7 +31,30 @@ #define MM_PORT_PROBE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PORT_PROBE, MMPortProbeClass)) /* Flags to request port probing */ -#define MM_PORT_PROBE_AT 0x0001 +#define MM_PORT_PROBE_AT 0x0001 +#define MM_PORT_PROBE_AT_CAPABILITIES 0x0002 + +/* Flags to report probed capabilities */ +#define MM_PORT_PROBE_CAPABILITY_GSM 0x0001 /* GSM */ +#define MM_PORT_PROBE_CAPABILITY_IS707_A 0x0002 /* CDMA Circuit Switched Data */ +#define MM_PORT_PROBE_CAPABILITY_IS707_P 0x0004 /* CDMA Packet Switched Data */ +#define MM_PORT_PROBE_CAPABILITY_DS 0x0008 /* Data compression selection (v.42bis) */ +#define MM_PORT_PROBE_CAPABILITY_ES 0x0010 /* Error control selection (v.42) */ +#define MM_PORT_PROBE_CAPABILITY_FCLASS 0x0020 /* Group III Fax */ +#define MM_PORT_PROBE_CAPABILITY_MS 0x0040 /* Modulation selection */ +#define MM_PORT_PROBE_CAPABILITY_W 0x0080 /* Wireless commands */ +#define MM_PORT_PROBE_CAPABILITY_IS856 0x0100 /* CDMA 3G EVDO rev 0 */ +#define MM_PORT_PROBE_CAPABILITY_IS856_A 0x0200 /* CDMA 3G EVDO rev A */ + +#define MM_PORT_PROBE_CAPABILITY_CDMA \ + (MM_PORT_PROBE_CAPABILITY_IS707_A | \ + MM_PORT_PROBE_CAPABILITY_IS707_P | \ + MM_PORT_PROBE_CAPABILITY_IS856 | \ + MM_PORT_PROBE_CAPABILITY_IS856_A) + +#define MM_PORT_PROBE_CAPABILITY_GSM_OR_CDMA \ + (MM_PORT_PROBE_CAPABILITY_CDMA | \ + MM_PORT_PROBE_CAPABILITY_GSM) typedef struct _MMPortProbe MMPortProbe; typedef struct _MMPortProbeClass MMPortProbeClass; @@ -70,7 +93,8 @@ gboolean mm_port_probe_run_finish (MMPortProbe *self, gboolean mm_port_probe_run_cancel (MMPortProbe *self); /* Probing result getters */ -gboolean mm_port_probe_is_at (MMPortProbe *self); +gboolean mm_port_probe_is_at (MMPortProbe *self); +guint32 mm_port_probe_get_capabilities (MMPortProbe *self); #endif /* MM_PORT_PROBE_H */ |