aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/mm-modem-hso.c200
-rw-r--r--plugins/mm-modem-option.c23
-rw-r--r--src/mm-generic-gsm.c43
-rw-r--r--src/mm-generic-gsm.h4
4 files changed, 220 insertions, 50 deletions
diff --git a/plugins/mm-modem-hso.c b/plugins/mm-modem-hso.c
index fa51bd30..28108ffd 100644
--- a/plugins/mm-modem-hso.c
+++ b/plugins/mm-modem-hso.c
@@ -9,7 +9,9 @@
#include <dbus/dbus-glib.h>
#include "mm-modem-hso.h"
#include "mm-serial.h"
+#include "mm-serial-parsers.h"
#include "mm-errors.h"
+#include "mm-util.h"
#include "mm-callback-info.h"
static void impl_hso_authenticate (MMModemHso *self,
@@ -28,7 +30,12 @@ static gpointer mm_modem_hso_parent_class = NULL;
typedef struct {
char *network_device;
- gboolean authenticated;
+ GRegex *connection_enabled_regex;
+ gpointer std_parser;
+
+ /* Pending connection attempt */
+ MMCallbackInfo *connect_pending_data;
+ guint connect_pending_id;
} MMModemHsoPrivate;
enum {
@@ -51,6 +58,7 @@ mm_modem_hso_new (const char *serial_device,
return MM_MODEM (g_object_new (MM_TYPE_MODEM_HSO,
MM_SERIAL_DEVICE, serial_device,
+ MM_SERIAL_SEND_DELAY, (guint64) 10000,
MM_MODEM_DRIVER, driver,
MM_MODEM_HSO_NETWORK_DEVICE, network_device,
NULL));
@@ -70,6 +78,18 @@ hso_enable_done (MMSerial *serial,
mm_callback_info_schedule (info);
}
+static guint32
+hso_get_cid (MMModemHso *self)
+{
+ guint32 cid;
+
+ cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self));
+ if (cid == 0)
+ cid = 1;
+
+ return cid;
+}
+
static void
hso_enable (MMModemHso *self,
gboolean enabled,
@@ -81,25 +101,61 @@ hso_enable (MMModemHso *self,
info = mm_callback_info_new (MM_MODEM (self), callback, user_data);
- command = g_strdup_printf ("AT_OWANCALL=%d,%d,1",
- mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)),
- enabled ? 1 : 0);
-
+ command = g_strdup_printf ("AT_OWANCALL=%d,%d,1", hso_get_cid (self), enabled ? 1 : 0);
mm_serial_queue_command (MM_SERIAL (self), command, 3, hso_enable_done, info);
g_free (command);
}
static void
+connect_pending_done (MMModemHso *self)
+{
+ MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self);
+
+ if (priv->connect_pending_data) {
+ mm_callback_info_schedule (priv->connect_pending_data);
+ priv->connect_pending_data = NULL;
+ }
+
+ if (priv->connect_pending_id) {
+ g_source_remove (priv->connect_pending_id);
+ priv->connect_pending_id = 0;
+ }
+}
+
+static gboolean
+hso_connect_timed_out (gpointer data)
+{
+ MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (data);
+
+ priv->connect_pending_data->error = g_error_new_literal (MM_SERIAL_ERROR,
+ MM_SERIAL_RESPONSE_TIMEOUT,
+ "Connection timed out");
+ connect_pending_done (MM_MODEM_HSO (data));
+
+ return FALSE;
+}
+
+static void
hso_enabled (MMModem *modem,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- if (error)
+ if (error) {
info->error = g_error_copy (error);
-
- mm_callback_info_schedule (info);
+ mm_callback_info_schedule (info);
+ } else {
+ MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (modem);
+ GSource *source;
+
+ source = g_timeout_source_new_seconds (30);
+ g_source_set_closure (source, g_cclosure_new_object (G_CALLBACK (hso_connect_timed_out), G_OBJECT (modem)));
+ g_source_attach (source, NULL);
+ priv->connect_pending_data = info;
+ priv->connect_pending_id = g_source_get_id (source);
+ g_source_unref (source);
+ }
}
static void
@@ -140,19 +196,24 @@ mm_hso_modem_authenticate (MMModemHso *self,
gpointer user_data)
{
MMCallbackInfo *info;
- char *command;
g_return_if_fail (MM_IS_MODEM_HSO (self));
g_return_if_fail (callback != NULL);
info = mm_callback_info_new (MM_MODEM (self), callback, user_data);
- command = g_strdup_printf ("AT$QCPDPP=%d,1,\"%s\",\"%s\"",
- mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)),
- password ? password : "",
- username ? username : "");
- mm_serial_queue_command (MM_SERIAL (self), command, 3, auth_done, info);
- g_free (command);
+ if (username || password) {
+ char *command;
+
+ command = g_strdup_printf ("AT$QCPDPP=%d,1,\"%s\",\"%s\"",
+ hso_get_cid (self),
+ password ? password : "",
+ username ? username : "");
+
+ mm_serial_queue_command (MM_SERIAL (self), command, 3, auth_done, info);
+ g_free (command);
+ } else
+ auth_done (MM_SERIAL (self), NULL, NULL, info);
}
static void
@@ -193,13 +254,13 @@ get_ip4_config_done (MMSerial *serial,
if (error) {
info->error = g_error_copy (error);
goto out;
- } else if (g_str_has_prefix (response->str, OWANDATA_TAG)) {
+ } else if (!g_str_has_prefix (response->str, OWANDATA_TAG)) {
info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
"Retrieving failed: invalid response.");
goto out;
}
- cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (serial));
+ cid = hso_get_cid (MM_MODEM_HSO (serial));
dns_array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 2);
items = g_strsplit (response->str + strlen (OWANDATA_TAG), ", ", 0);
@@ -249,7 +310,7 @@ mm_hso_modem_get_ip4_config (MMModemHso *self,
mm_callback_info_set_data (info, "callback", callback, NULL);
mm_callback_info_set_data (info, "user-data", user_data, NULL);
- command = g_strdup_printf ("AT_OWANDATA=%d", mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)));
+ command = g_strdup_printf ("AT_OWANDATA=%d", hso_get_cid (self));
mm_serial_queue_command (MM_SERIAL (self), command, 3, get_ip4_config_done, info);
g_free (command);
}
@@ -257,16 +318,45 @@ mm_hso_modem_get_ip4_config (MMModemHso *self,
/*****************************************************************************/
static void
-modem_enable_done (MMModem *modem, GError *error, gpointer user_data)
+pin_check_done (MMModem *modem, GError *error, gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ if (error)
+ info->error = g_error_copy (error);
+ mm_callback_info_schedule (info);
+}
+
+static void
+parent_enable_done (MMModem *modem, GError *error, gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ if (error) {
+ info->error = g_error_copy (error);
+ mm_callback_info_schedule (info);
+ } else if (GPOINTER_TO_INT (mm_callback_info_get_data (info, "enable")) == FALSE) {
+ /* Disable, we're done */
+ mm_callback_info_schedule (info);
+ } else {
+ /* HSO needs manual PIN checking */
+ mm_generic_gsm_check_pin (MM_GENERIC_GSM (modem), pin_check_done, info);
+ }
+}
+
+static void
+modem_enable_done (MMSerial *serial,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMModem *parent_modem_iface;
- parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem));
- parent_modem_iface->enable (modem,
+ parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (serial));
+ parent_modem_iface->enable (MM_MODEM (serial),
GPOINTER_TO_INT (mm_callback_info_get_data (info, "enable")),
- (MMModemFn) mm_callback_info_get_data (info, "callback"),
- mm_callback_info_get_data (info, "user-data"));
+ parent_enable_done, info);
}
static void
@@ -277,16 +367,25 @@ enable (MMModem *modem,
{
MMCallbackInfo *info;
- info = mm_callback_info_new (modem, modem_enable_done, NULL);
- info->user_data = info;
+ info = mm_callback_info_new (modem, callback, user_data);
mm_callback_info_set_data (info, "enable", GINT_TO_POINTER (enable), NULL);
- mm_callback_info_set_data (info, "callback", callback, NULL);
- mm_callback_info_set_data (info, "user-data", user_data, NULL);
if (enable)
- mm_callback_info_schedule (info);
+ modem_enable_done (MM_SERIAL (modem), NULL, NULL, info);
else
- hso_enable (MM_MODEM_HSO (modem), FALSE, modem_enable_done, info);
+ mm_serial_queue_command (MM_SERIAL (modem), "AT_OWANCALL=1,0,0", 3, modem_enable_done, info);
+}
+
+static void
+do_connect (MMModem *modem,
+ const char *number,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new (modem, callback, user_data);
+ mm_callback_info_schedule (info);
}
/*****************************************************************************/
@@ -310,6 +409,12 @@ impl_hso_authenticate (MMModemHso *self,
const char *password,
DBusGMethodInvocation *context)
{
+ /* DBus doesn't support NULLs */
+ if (username && strlen (username) == 0)
+ username = NULL;
+ if (password && strlen (password) == 0)
+ password = NULL;
+
mm_hso_modem_authenticate (self, username, password, impl_hso_auth_done, context);
}
@@ -335,17 +440,47 @@ impl_hso_get_ip4_config (MMModemHso *self,
mm_hso_modem_get_ip4_config (self, impl_hso_ip4_config_done, context);
}
+static void
+connection_enabled (const char *str, gpointer data)
+{
+ if (str && strlen (str) == 4) {
+ if (str[3] == '1')
+ connect_pending_done (MM_MODEM_HSO (data));
+ if (str[3] == '0')
+ /* FIXME: disconnected. do something when we have modem status signals */
+ ;
+ }
+}
+
+static gboolean
+hso_parse_response (gpointer data, GString *response, GError **error)
+{
+ MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (data);
+
+ mm_util_strip_string (response, priv->connection_enabled_regex, connection_enabled, data);
+
+ return mm_serial_parser_v1_parse (priv->std_parser, response, error);
+}
+
/*****************************************************************************/
static void
mm_modem_hso_init (MMModemHso *self)
{
+ MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self);
+
+ priv->connection_enabled_regex = g_regex_new ("_OWANCALL: (\\d, \\d)\\r\\n",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+
+ priv->std_parser = (gpointer) mm_serial_parser_v1_new ();
+ mm_serial_set_response_parser (MM_SERIAL (self), hso_parse_response, self, NULL);
}
static void
modem_init (MMModem *modem_class)
{
modem_class->enable = enable;
+ modem_class->connect = do_connect;
}
static GObject*
@@ -410,7 +545,12 @@ finalize (GObject *object)
{
MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (object);
+ /* Clear the pending connection if necessary */
+ connect_pending_done (MM_MODEM_HSO (object));
+
g_free (priv->network_device);
+ g_regex_unref (priv->connection_enabled_regex);
+ mm_serial_parser_v1_destroy (priv->std_parser);
G_OBJECT_CLASS (mm_modem_hso_parent_class)->finalize (object);
}
@@ -462,6 +602,8 @@ mm_modem_hso_get_type (void)
modem_hso_type = g_type_register_static (MM_TYPE_GENERIC_GSM, "MMModemHso", &modem_hso_type_info, 0);
g_type_add_interface_static (modem_hso_type, MM_TYPE_MODEM, &modem_iface_info);
+
+ dbus_g_object_type_install_info (modem_hso_type, &dbus_glib_mm_modem_gsm_hso_object_info);
}
return modem_hso_type;
diff --git a/plugins/mm-modem-option.c b/plugins/mm-modem-option.c
index c5800d8f..a45bc36e 100644
--- a/plugins/mm-modem-option.c
+++ b/plugins/mm-modem-option.c
@@ -24,31 +24,12 @@ mm_modem_option_new (const char *data_device,
}
static void
-check_pin_done (MMSerial *serial,
- GString *response,
- GError *error,
- gpointer user_data)
+pin_check_done (MMModem *modem, GError *error, gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- gboolean parsed = FALSE;
if (error)
info->error = g_error_copy (error);
- else if (g_str_has_prefix (response->str, "+CPIN: ")) {
- const char *str = response->str + 7;
-
- if (g_str_has_prefix (str, "READY"))
- parsed = TRUE;
- else if (g_str_has_prefix (str, "SIM PIN"))
- info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_SIM_PIN);
- else if (g_str_has_prefix (str, "SIM PUK"))
- info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_SIM_PUK);
- }
-
- if (!info->error && !parsed)
- info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "%s", "Could not parse PIN request results");
-
mm_callback_info_schedule (info);
}
@@ -66,7 +47,7 @@ parent_enable_done (MMModem *modem, GError *error, gpointer user_data)
/* Now check the PIN explicitly, option doesn't seem to report
that it needs it otherwise */
- mm_serial_queue_command (MM_SERIAL (modem), "+CPIN?", 3, check_pin_done, info);
+ mm_generic_gsm_check_pin (MM_GENERIC_GSM (modem), pin_check_done, info);
return;
}
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index 2f0be962..e1769c8d 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -85,6 +85,49 @@ mm_generic_gsm_set_operator (MMGenericGsm *modem,
priv->oper_name = g_strdup (name);
}
+static void
+pin_check_done (MMSerial *serial,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ gboolean parsed = FALSE;
+
+ if (error)
+ info->error = g_error_copy (error);
+ else if (g_str_has_prefix (response->str, "+CPIN: ")) {
+ const char *str = response->str + 7;
+
+ if (g_str_has_prefix (str, "READY"))
+ parsed = TRUE;
+ else if (g_str_has_prefix (str, "SIM PIN"))
+ info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_SIM_PIN);
+ else if (g_str_has_prefix (str, "SIM PUK"))
+ info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_SIM_PUK);
+ /* FIXME: There's more exotic ones that are not handled right now */
+ }
+
+ if (!info->error && !parsed)
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "%s", "Could not parse PIN request results");
+
+ mm_callback_info_schedule (info);
+}
+
+void
+mm_generic_gsm_check_pin (MMGenericGsm *modem,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ g_return_if_fail (MM_IS_GENERIC_GSM (modem));
+
+ info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
+ mm_serial_queue_command (MM_SERIAL (modem), "+CPIN?", 3, pin_check_done, info);
+}
+
/*****************************************************************************/
static void
diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h
index 621bad7f..ec8428f5 100644
--- a/src/mm-generic-gsm.h
+++ b/src/mm-generic-gsm.h
@@ -37,4 +37,8 @@ void mm_generic_gsm_set_operator (MMGenericGsm *modem,
const char *code,
const char *name);
+void mm_generic_gsm_check_pin (MMGenericGsm *modem,
+ MMModemFn callback,
+ gpointer user_data);
+
#endif /* MM_GENERIC_GSM_H */