diff options
-rw-r--r-- | introspection/Makefile.am | 1 | ||||
-rw-r--r-- | introspection/all.xml | 1 | ||||
-rw-r--r-- | introspection/mm-gsm-modem-hso.xml | 41 | ||||
-rw-r--r-- | plugins/Makefile.am | 30 | ||||
-rw-r--r-- | plugins/mm-modem-hso.c | 500 | ||||
-rw-r--r-- | plugins/mm-modem-hso.h | 49 | ||||
-rw-r--r-- | plugins/mm-plugin-hso.c | 183 | ||||
-rw-r--r-- | plugins/mm-plugin-hso.h | 26 | ||||
-rw-r--r-- | src/mm-generic-gsm.c | 18 | ||||
-rw-r--r-- | src/mm-gsm-modem.c | 14 | ||||
-rw-r--r-- | src/mm-gsm-modem.h | 8 |
11 files changed, 862 insertions, 9 deletions
diff --git a/introspection/Makefile.am b/introspection/Makefile.am index f003f098..0716ab43 100644 --- a/introspection/Makefile.am +++ b/introspection/Makefile.am @@ -2,4 +2,5 @@ EXTRA_DIST = \ mm-manager.xml \ mm-modem.xml \ mm-gsm-modem.xml \ + mm-gsm-modem-hso.xml \ mm-cdma-modem.xml diff --git a/introspection/all.xml b/introspection/all.xml index c7d6779a..22958f1e 100644 --- a/introspection/all.xml +++ b/introspection/all.xml @@ -26,4 +26,5 @@ <xi:include href="mm-modem.xml"/> <xi:include href="mm-cdma-modem.xml"/> <xi:include href="mm-gsm-modem.xml"/> + <xi:include href="mm-gsm-modem-hso.xml"/> </tp:spec> diff --git a/introspection/mm-gsm-modem-hso.xml b/introspection/mm-gsm-modem-hso.xml new file mode 100644 index 00000000..d994ca64 --- /dev/null +++ b/introspection/mm-gsm-modem-hso.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> + + <interface name="org.freedesktop.ModemManager.Modem.Gsm.Hso"> + <method name="GetIP4Config"> + <tp:docstring> + Request the IP4 configuration from the device. + </tp:docstring> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_hso_get_ip4_config"/> + <arg name="address" type="u" direction="out"> + The IP4 address. + </arg> + <arg name="dns" type="au" direction="out"> + The DNS addresses. + </arg> + </method> + + <method name="Authenticate"> + <tp:docstring> + Authenticate using the passed user name and password. + </tp:docstring> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_hso_authenticate"/> + <arg name="username" type="s" direction="in"> + The user name. + </arg> + <arg name="password" type="s" direction="in"> + The password. + </arg> + </method> + + <property name="NetworkDevice" type="s" access="read"> + <tp:docstring> + The network device. + </tp:docstring> + </property> + + </interface> +</node> diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 1ca505ac..9236685c 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -1,5 +1,8 @@ pkglib_LTLIBRARIES = \ - libmm-plugin-huawei.la + libmm-plugin-huawei.la \ + libmm-plugin-hso.la + +# Huawei libmm_plugin_huawei_la_SOURCES = \ mm-modem-huawei.c \ @@ -11,4 +14,27 @@ libmm_plugin_huawei_la_CPPFLAGS = \ $(MM_CFLAGS) \ -I$(top_srcdir)/src -libmm_plugin_huawei_la_LDFLAGS = -modeule -avoid-version +libmm_plugin_huawei_la_LDFLAGS = -module -avoid-version + +# HSO + +libmm_plugin_hso_la_SOURCES = \ + mm-gsm-modem-hso-glue.h \ + mm-modem-hso.c \ + mm-modem-hso.h \ + mm-plugin-hso.c \ + mm-plugin-hso.h + +mm-gsm-modem-hso-glue.h: $(top_srcdir)/introspection/mm-gsm-modem-hso.xml + dbus-binding-tool --prefix=mm_gsm_modem_hso --mode=glib-server --output=$@ $< + +libmm_plugin_hso_la_CPPFLAGS = \ + $(MM_CFLAGS) \ + -I$(top_srcdir)/src + +libmm_plugin_hso_la_LDFLAGS = -module -avoid-version + +BUILT_SOURCES = \ + mm-gsm-modem-hso-glue.h + +CLEANFILES = $(BUILT_SOURCES) diff --git a/plugins/mm-modem-hso.c b/plugins/mm-modem-hso.c new file mode 100644 index 00000000..0153d816 --- /dev/null +++ b/plugins/mm-modem-hso.c @@ -0,0 +1,500 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <arpa/inet.h> +#include <dbus/dbus-glib.h> +#include "mm-modem-hso.h" +#include "mm-serial.h" +#include "mm-gsm-modem.h" +#include "mm-modem-error.h" +#include "mm-callback-info.h" + +static void impl_hso_get_ip4_config (MMModemHso *self, DBusGMethodInvocation *context); +static void impl_hso_authenticate (MMModemHso *self, + const char *username, + const char *password, + DBusGMethodInvocation *context); + +#include "mm-gsm-modem-hso-glue.h" + +static gpointer mm_modem_hso_parent_class = NULL; + +#define MM_MODEM_HSO_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_HSO, MMModemHsoPrivate)) + +typedef struct { + char *network_device; + gboolean authenticated; +} MMModemHsoPrivate; + +enum { + PROP_0, + PROP_NETWORK_DEVICE, + + LAST_PROP +}; + +#define OWANDATA_TAG "_OWANDATA: " + +MMModem * +mm_modem_hso_new (const char *serial_device, + const char *network_device, + const char *driver) +{ + g_return_val_if_fail (serial_device != NULL, NULL); + g_return_val_if_fail (network_device != NULL, NULL); + g_return_val_if_fail (driver != NULL, NULL); + + return MM_MODEM (g_object_new (MM_TYPE_MODEM_HSO, + MM_SERIAL_DEVICE, serial_device, + MM_MODEM_DRIVER, driver, + MM_MODEM_HSO_NETWORK_DEVICE, network_device, + NULL)); +} + +/*****************************************************************************/ + +static void +need_auth_done (MMModem *modem, GError *error, gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMModemFn callback; + + if (!MM_MODEM_HSO_GET_PRIVATE (modem)->authenticated) + /* Re-use the PIN_NEEDED error as HSO never needs PIN or PUK, right? */ + error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_PIN_NEEDED, "%s", "Authentication needed."); + + callback = mm_callback_info_get_data (info, "callback"); + callback (MM_MODEM (modem), + error, + mm_callback_info_get_data (info, "user-data")); +} + +static void +need_auth (MMModem *modem, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + + info = mm_callback_info_new (modem, need_auth_done, NULL); + info->user_data = info; + mm_callback_info_set_data (info, "callback", callback, NULL); + mm_callback_info_set_data (info, "user-data", user_data, NULL); + + mm_callback_info_schedule (info); +} + +static void +call_done (MMSerial *serial, + int reply_index, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + switch (reply_index) { + case 0: + /* Success */ + break; + default: + info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dial failed."); + break; + } + + mm_callback_info_schedule (info); +} + +static void +clear_done (MMSerial *serial, + int reply_index, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + char *command; + char *responses[] = { "_OWANCALL: ", "ERROR", NULL }; + guint id = 0; + + /* FIXME: Ignore errors here? */ + /* Try to connect */ + command = g_strdup_printf ("AT_OWANCALL=%d,1,1", mm_generic_gsm_get_cid (MM_GENERIC_GSM (serial))); + if (mm_serial_send_command_string (serial, command)) + id = mm_serial_wait_for_reply (serial, 10, responses, responses, call_done, user_data); + + g_free (command); + + if (!id) { + info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dial failed."); + mm_callback_info_schedule (info); + } +} + +static void +do_connect (MMModem *modem, + const char *number, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + char *command; + char *responses[] = { "_OWANCALL: ", "ERROR", "NO CARRIER", NULL }; + guint id = 0; + + info = mm_callback_info_new (modem, callback, user_data); + + /* Kill any existing connection first */ + command = g_strdup_printf ("AT_OWANCALL=%d,0,1", mm_generic_gsm_get_cid (MM_GENERIC_GSM (modem))); + if (mm_serial_send_command_string (MM_SERIAL (modem), command)) + id = mm_serial_wait_for_reply (MM_SERIAL (modem), 5, responses, responses, clear_done, user_data); + + g_free (command); + + if (!id) { + info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dial failed."); + mm_callback_info_schedule (info); + } +} + +static void +free_dns_array (gpointer data) +{ + g_array_free ((GArray *) data, TRUE); +} + +static void +ip4_callback_wrapper (MMModem *modem, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMModemHsoIp4Fn callback; + + callback = mm_callback_info_get_data (info, "callback"); + callback (MM_MODEM_HSO (modem), + GPOINTER_TO_UINT (mm_callback_info_get_data (info, "ip4-address")), + mm_callback_info_get_data (info, "ip4-dns"), + error, + mm_callback_info_get_data (info, "user-data")); +} + +static void +get_ip4_config_done (MMSerial *serial, const char *response, gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + char **items, **iter; + GArray *dns_array; + int i; + guint32 tmp; + guint cid; + + if (!response || strncmp (response, OWANDATA_TAG, strlen (OWANDATA_TAG))) { + info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", + "Retrieving failed: invalid response."); + goto out; + } + + cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (serial)); + dns_array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 2); + items = g_strsplit (response + strlen (OWANDATA_TAG), ", ", 0); + + for (iter = items, i = 0; *iter; iter++, i++) { + if (i == 0) { /* CID */ + long int tmp; + + errno = 0; + tmp = strtol (*iter, NULL, 10); + if (errno != 0 || tmp < 0 || (guint) tmp != cid) { + info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Unknown CID in OWANDATA response (got %d, expected %d)", (guint) tmp, cid); + break; + } + } else if (i == 1) { /* IP address */ + if (inet_pton (AF_INET, *iter, &tmp) > 0) + mm_callback_info_set_data (info, "ip4-address", GUINT_TO_POINTER (tmp), NULL); + } else if (i == 3) { /* DNS 1 */ + if (inet_pton (AF_INET, *iter, &tmp) > 0) + g_array_append_val (dns_array, tmp); + } else if (i == 4) { /* DNS 2 */ + if (inet_pton (AF_INET, *iter, &tmp) > 0) + g_array_append_val (dns_array, tmp); + } + } + + g_strfreev (items); + mm_callback_info_set_data (info, "ip4-dns", dns_array, free_dns_array); + + out: + mm_callback_info_schedule (info); +} + +void +mm_hso_modem_get_ip4_config (MMModemHso *self, + MMModemHsoIp4Fn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + char *command; + const char terminators[] = { '\r', '\n', '\0' }; + guint id = 0; + + g_return_if_fail (MM_IS_MODEM_HSO (self)); + g_return_if_fail (callback != NULL); + + info = mm_callback_info_new (MM_MODEM (self), ip4_callback_wrapper, NULL); + info->user_data = info; + 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))); + if (mm_serial_send_command_string (MM_SERIAL (self), command)) + id = mm_serial_get_reply (MM_SERIAL (self), 5, terminators, get_ip4_config_done, info); + + g_free (command); + + if (!id) { + info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Retrieving failed."); + mm_callback_info_schedule (info); + } +} + +static void +impl_hso_ip4_config_done (MMModemHso *modem, + guint32 address, + GArray *dns, + GError *error, + gpointer user_data) +{ + DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data; + + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context, address, dns); +} + +static void +impl_hso_get_ip4_config (MMModemHso *self, + DBusGMethodInvocation *context) +{ + mm_hso_modem_get_ip4_config (self, impl_hso_ip4_config_done, context); +} + +static void +auth_done (MMSerial *serial, + int reply_index, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + switch (reply_index) { + case 0: + /* success */ + MM_MODEM_HSO_GET_PRIVATE (serial)->authenticated = TRUE; + break; + default: + info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Authentication failed"); + break; + } + + mm_callback_info_schedule (info); +} + +void +mm_hso_modem_authenticate (MMModemHso *self, + const char *username, + const char *password, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + char *command; + char *responses[] = { "OK", "ERROR", NULL }; + guint id = 0; + + 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 : ""); + + if (mm_serial_send_command_string (MM_SERIAL (self), command)) + id = mm_serial_wait_for_reply (MM_SERIAL (self), 5, responses, responses, auth_done, user_data); + + g_free (command); + + if (!id) { + info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Authentication failed."); + mm_callback_info_schedule (info); + } +} + +static void +impl_hso_auth_done (MMModem *modem, + GError *error, + gpointer user_data) +{ + DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data; + + if (error) + dbus_g_method_return_error (context, error); + else + dbus_g_method_return (context); +} + +static void +impl_hso_authenticate (MMModemHso *self, + const char *username, + const char *password, + DBusGMethodInvocation *context) +{ + mm_hso_modem_authenticate (self, username, password, impl_hso_auth_done, context); +} + +/*****************************************************************************/ + +static void +modem_init (MMModem *modem_class) +{ + modem_class->connect = do_connect; +} + +static void +gsm_modem_init (MMGsmModem *gsm_modem_class) +{ + gsm_modem_class->need_authentication = need_auth; +} + +static void +mm_modem_hso_init (MMModemHso *self) +{ +} + +static GObject* +constructor (GType type, + guint n_construct_params, + GObjectConstructParam *construct_params) +{ + GObject *object; + MMModemHsoPrivate *priv; + + object = G_OBJECT_CLASS (mm_modem_hso_parent_class)->constructor (type, + n_construct_params, + construct_params); + if (!object) + return NULL; + + priv = MM_MODEM_HSO_GET_PRIVATE (object); + + if (!priv->network_device) { + g_warning ("No network device provided"); + g_object_unref (object); + return NULL; + } + + return object; +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_NETWORK_DEVICE: + /* Construct only */ + priv->network_device = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_NETWORK_DEVICE: + g_value_set_string (value, priv->network_device); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} +static void +finalize (GObject *object) +{ + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (object); + + g_free (priv->network_device); + + G_OBJECT_CLASS (mm_modem_hso_parent_class)->finalize (object); +} + +static void +mm_modem_hso_class_init (MMModemHsoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + mm_modem_hso_parent_class = g_type_class_peek_parent (klass); + g_type_class_add_private (object_class, sizeof (MMModemHsoPrivate)); + + /* Virtual methods */ + object_class->constructor = constructor; + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; + /* Properties */ + g_object_class_install_property + (object_class, PROP_NETWORK_DEVICE, + g_param_spec_string (MM_MODEM_HSO_NETWORK_DEVICE, + "NetworkDevice", + "Network device", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + +GType +mm_modem_hso_get_type (void) +{ + static GType modem_hso_type = 0; + + if (G_UNLIKELY (modem_hso_type == 0)) { + static const GTypeInfo modem_hso_type_info = { + sizeof (MMModemHsoClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) mm_modem_hso_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (MMModemHso), + 0, /* n_preallocs */ + (GInstanceInitFunc) mm_modem_hso_init, + }; + + static const GInterfaceInfo modem_iface_info = { + (GInterfaceInitFunc) modem_init + }; + + static const GInterfaceInfo gsm_modem_iface_info = { + (GInterfaceInitFunc) gsm_modem_init + }; + + 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); + g_type_add_interface_static (modem_hso_type, MM_TYPE_GSM_MODEM, &gsm_modem_iface_info); + } + + return modem_hso_type; +} diff --git a/plugins/mm-modem-hso.h b/plugins/mm-modem-hso.h new file mode 100644 index 00000000..343b0fed --- /dev/null +++ b/plugins/mm-modem-hso.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +#ifndef MM_MODEM_HSO_H +#define MM_MODEM_HSO_H + +#include "mm-generic-gsm.h" + +#define MM_TYPE_MODEM_HSO (mm_modem_hso_get_type ()) +#define MM_MODEM_HSO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_HSO, MMModemHso)) +#define MM_MODEM_HSO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_HSO, MMModemHsoClass)) +#define MM_IS_MODEM_HSO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_HSO)) +#define MM_IS_MODEM_HSO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_HSO)) +#define MM_MODEM_HSO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_HSO, MMModemHsoClass)) + +#define MM_MODEM_HSO_NETWORK_DEVICE "network-device" + +typedef struct { + MMGenericGsm parent; +} MMModemHso; + +typedef struct { + MMGenericGsmClass parent; +} MMModemHsoClass; + +typedef void (*MMModemHsoIp4Fn) (MMModemHso *modem, + guint32 address, + GArray *dns, + GError *error, + gpointer user_data); + + +GType mm_modem_hso_get_type (void); + +MMModem *mm_modem_hso_new (const char *serial_device, + const char *network_device, + const char *driver); + +void mm_hso_modem_authenticate (MMModemHso *self, + const char *username, + const char *password, + MMModemFn callback, + gpointer user_data); + +void mm_hso_modem_get_ip4_config (MMModemHso *self, + MMModemHsoIp4Fn callback, + gpointer user_data); + + +#endif /* MM_MODEM_HSO_H */ diff --git a/plugins/mm-plugin-hso.c b/plugins/mm-plugin-hso.c new file mode 100644 index 00000000..c64fc12e --- /dev/null +++ b/plugins/mm-plugin-hso.c @@ -0,0 +1,183 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +#include <string.h> +#include <gmodule.h> +#include "mm-plugin-hso.h" +#include "mm-modem-hso.h" + +static void plugin_init (MMPlugin *plugin_class); + +G_DEFINE_TYPE_EXTENDED (MMPluginHso, mm_plugin_hso, G_TYPE_OBJECT, + 0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init)) + +int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION; +int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION; + +G_MODULE_EXPORT MMPlugin * +mm_plugin_create (void) +{ + return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_HSO, NULL)); +} + +/*****************************************************************************/ + +static const char * +get_name (MMPlugin *plugin) +{ + return "HSO"; +} + +static char ** +list_supported_udis (MMPlugin *plugin, LibHalContext *hal_ctx) +{ + char **supported = NULL; + char **devices; + int num_devices; + int i; + + devices = libhal_find_device_by_capability (hal_ctx, "modem", &num_devices, NULL); + if (devices) { + GPtrArray *array; + + array = g_ptr_array_new (); + + for (i = 0; i < num_devices; i++) { + char *udi = devices[i]; + + if (mm_plugin_supports_udi (plugin, hal_ctx, udi)) + g_ptr_array_add (array, g_strdup (udi)); + } + + if (array->len > 0) { + g_ptr_array_add (array, NULL); + supported = (char **) g_ptr_array_free (array, FALSE); + } else + g_ptr_array_free (array, TRUE); + } + + g_strfreev (devices); + + return supported; +} + +static char * +get_driver_name (LibHalContext *ctx, const char *udi) +{ + char *parent_udi; + char *driver = NULL; + + parent_udi = libhal_device_get_property_string (ctx, udi, "info.parent", NULL); + if (parent_udi) { + driver = libhal_device_get_property_string (ctx, parent_udi, "info.linux.driver", NULL); + libhal_free_string (parent_udi); + } + + return driver; +} + +static gboolean +supports_udi (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi) +{ + char *driver_name; + gboolean supported = FALSE; + + driver_name = get_driver_name (hal_ctx, udi); + if (driver_name && !strcmp (driver_name, "hso")) + supported = TRUE; + + libhal_free_string (driver_name); + + return supported; +} + +static char * +get_netdev (LibHalContext *ctx, const char *udi) +{ + char *serial_parent, *netdev = NULL; + char **netdevs; + int num, i; + + /* Get the serial interface's originating device UDI, used to find the + * originating device's netdev. + */ + serial_parent = libhal_device_get_property_string (ctx, udi, "serial.originating_device", NULL); + if (!serial_parent) + serial_parent = libhal_device_get_property_string (ctx, udi, "info.parent", NULL); + if (!serial_parent) + return NULL; + + /* Look for the originating device's netdev */ + netdevs = libhal_find_device_by_capability (ctx, "net", &num, NULL); + for (i = 0; netdevs && !netdev && (i < num); i++) { + char *netdev_parent, *tmp; + + netdev_parent = libhal_device_get_property_string (ctx, netdevs[i], "net.originating_device", NULL); + if (!netdev_parent) + netdev_parent = libhal_device_get_property_string (ctx, netdevs[i], "net.physical_device", NULL); + if (!netdev_parent) + continue; + + if (!strcmp (netdev_parent, serial_parent)) { + /* We found it */ + tmp = libhal_device_get_property_string (ctx, netdevs[i], "net.interface", NULL); + if (tmp) { + netdev = g_strdup (tmp); + libhal_free_string (tmp); + } + } + + libhal_free_string (netdev_parent); + } + libhal_free_string_array (netdevs); + libhal_free_string (serial_parent); + + return netdev; +} + +static MMModem * +create_modem (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi) +{ + char *serial_device; + char *net_device; + char *driver; + MMModem *modem; + + serial_device = libhal_device_get_property_string (hal_ctx, udi, "serial.device", NULL); + g_return_val_if_fail (serial_device != NULL, NULL); + + driver = get_driver_name (hal_ctx, udi); + g_return_val_if_fail (driver != NULL, NULL); + + net_device = get_netdev (hal_ctx, udi); + g_return_val_if_fail (net_device != NULL, NULL); + + modem = MM_MODEM (mm_modem_hso_new (serial_device, net_device, driver)); + + g_free (serial_device); + g_free (net_device); + g_free (driver); + + return modem; +} + +/*****************************************************************************/ + +static void +plugin_init (MMPlugin *plugin_class) +{ + /* interface implementation */ + plugin_class->get_name = get_name; + plugin_class->list_supported_udis = list_supported_udis; + plugin_class->supports_udi = supports_udi; + plugin_class->create_modem = create_modem; +} + +static void +mm_plugin_hso_init (MMPluginHso *self) +{ +} + +static void +mm_plugin_hso_class_init (MMPluginHsoClass *klass) +{ +} diff --git a/plugins/mm-plugin-hso.h b/plugins/mm-plugin-hso.h new file mode 100644 index 00000000..f8ead6d6 --- /dev/null +++ b/plugins/mm-plugin-hso.h @@ -0,0 +1,26 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +#ifndef MM_PLUGIN_HSO_H +#define MM_PLUGIN_HSO_H + +#include "mm-plugin.h" +#include "mm-generic-gsm.h" + +#define MM_TYPE_PLUGIN_HSO (mm_plugin_hso_get_type ()) +#define MM_PLUGIN_HSO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_HSO, MMPluginHso)) +#define MM_PLUGIN_HSO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_HSO, MMPluginHsoClass)) +#define MM_IS_PLUGIN_HSO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_HSO)) +#define MM_IS_PLUGIN_HSO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_HSO)) +#define MM_PLUGIN_HSO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_HSO, MMPluginHsoClass)) + +typedef struct { + GObject parent; +} MMPluginHso; + +typedef struct { + GObjectClass parent; +} MMPluginHsoClass; + +GType mm_plugin_hso_get_type (void); + +#endif /* MM_PLUGIN_HSO_H */ diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index 1c089c1e..80b85b61 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -73,7 +73,7 @@ mm_generic_gsm_set_operator (MMGenericGsm *modem, /*****************************************************************************/ static void -check_pin_done (MMSerial *serial, +need_auth_done (MMSerial *serial, int reply_index, gpointer user_data) { @@ -101,18 +101,21 @@ check_pin_done (MMSerial *serial, } static void -check_pin (MMSerial *serial, gpointer user_data) +need_auth (MMGsmModem *modem, + MMModemFn callback, + gpointer user_data) { + MMCallbackInfo *info; char *responses[] = { "READY", "SIM PIN", "SIM PUK", "ERROR", "ERR", NULL }; char *terminators[] = { "OK", "ERROR", "ERR", NULL }; guint id = 0; - if (mm_serial_send_command_string (serial, "AT+CPIN?")) - id = mm_serial_wait_for_reply (serial, 3, responses, terminators, check_pin_done, user_data); + info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); + + if (mm_serial_send_command_string (MM_SERIAL (modem), "AT+CPIN?")) + id = mm_serial_wait_for_reply (MM_SERIAL (modem), 3, responses, terminators, need_auth_done, info); if (!id) { - MMCallbackInfo *info = (MMCallbackInfo *) user_data; - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "PIN checking failed."); mm_callback_info_schedule (info); } @@ -128,7 +131,7 @@ init_done (MMSerial *serial, switch (reply_index) { case 0: /* success */ - check_pin (serial, user_data); + mm_gsm_modem_need_authentication (MM_GSM_MODEM (serial), info->callback, info->user_data); break; case -1: info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Modem initialization timed out."); @@ -839,6 +842,7 @@ modem_init (MMModem *modem_class) static void gsm_modem_init (MMGsmModem *gsm_modem_class) { + gsm_modem_class->need_authentication = need_auth; gsm_modem_class->set_pin = set_pin; gsm_modem_class->do_register = do_register; gsm_modem_class->get_registration_info = get_registration_info; diff --git a/src/mm-gsm-modem.c b/src/mm-gsm-modem.c index 29dc8c21..717391a0 100644 --- a/src/mm-gsm-modem.c +++ b/src/mm-gsm-modem.c @@ -77,6 +77,20 @@ uint_call_done (MMModem *modem, guint32 result, GError *error, gpointer user_dat } void +mm_gsm_modem_need_authentication (MMGsmModem *self, + MMModemFn callback, + gpointer user_data) +{ + g_return_if_fail (MM_IS_GSM_MODEM (self)); + g_return_if_fail (callback != NULL); + + if (MM_GSM_MODEM_GET_INTERFACE (self)->need_authentication) + MM_GSM_MODEM_GET_INTERFACE (self)->need_authentication (self, callback, user_data); + else + async_op_not_supported (MM_MODEM (self), callback, user_data); +} + +void mm_gsm_modem_set_pin (MMGsmModem *self, const char *pin, MMModemFn callback, diff --git a/src/mm-gsm-modem.h b/src/mm-gsm-modem.h index ea51f4fb..ee356ae9 100644 --- a/src/mm-gsm-modem.h +++ b/src/mm-gsm-modem.h @@ -66,6 +66,10 @@ struct _MMGsmModem { GTypeInterface g_iface; /* Methods */ + void (*need_authentication) (MMGsmModem *self, + MMModemFn callback, + gpointer user_data); + void (*set_pin) (MMGsmModem *self, const char *pin, MMModemFn callback, @@ -122,6 +126,10 @@ struct _MMGsmModem { GType mm_gsm_modem_get_type (void); +void mm_gsm_modem_need_authentication (MMGsmModem *self, + MMModemFn callback, + gpointer user_data); + void mm_gsm_modem_set_pin (MMGsmModem *self, const char *pin, MMModemFn callback, |