aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am24
-rw-r--r--src/main.c125
-rw-r--r--src/mm-errors.c2
-rw-r--r--src/mm-generic-cdma.c466
-rw-r--r--src/mm-generic-cdma.h23
-rw-r--r--src/mm-generic-gsm.c580
-rw-r--r--src/mm-generic-gsm.h48
-rw-r--r--src/mm-manager.c561
-rw-r--r--src/mm-manager.h6
-rw-r--r--src/mm-modem-base.c156
-rw-r--r--src/mm-modem-base.h59
-rw-r--r--src/mm-modem-cdma.c136
-rw-r--r--src/mm-modem-cdma.h23
-rw-r--r--src/mm-modem-gsm-card.c86
-rw-r--r--src/mm-modem-gsm-card.h15
-rw-r--r--src/mm-modem.c181
-rw-r--r--src/mm-modem.h71
-rw-r--r--src/mm-plugin-base.c950
-rw-r--r--src/mm-plugin-base.h145
-rw-r--r--src/mm-plugin.c57
-rw-r--r--src/mm-plugin.h97
-rw-r--r--src/mm-port.c238
-rw-r--r--src/mm-port.h74
-rw-r--r--src/mm-serial-parsers.c8
-rw-r--r--src/mm-serial-port.c (renamed from src/mm-serial.c)387
-rw-r--r--src/mm-serial-port.h105
-rw-r--r--src/mm-serial.h89
27 files changed, 3737 insertions, 975 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index d6d4e73f..b8374fef 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,27 +2,37 @@ sbin_PROGRAMS = modem-manager
modem_manager_CPPFLAGS = \
$(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
-I${top_builddir}/marshallers \
-DPLUGINDIR=\"$(pkglibdir)\"
modem_manager_LDADD = \
$(MM_LIBS) \
+ $(GUDEV_LIBS) \
$(top_builddir)/marshallers/libmarshallers.la
modem_manager_SOURCES = \
main.c \
mm-callback-info.c \
mm-callback-info.h \
- mm-generic-cdma.c \
- mm-generic-cdma.h \
- mm-generic-gsm.c \
- mm-generic-gsm.h \
mm-errors.c \
mm-errors.h \
mm-manager.c \
mm-manager.h \
mm-modem.c \
mm-modem.h \
+ mm-port.c \
+ mm-port.h \
+ mm-modem-base.c \
+ mm-modem-base.h \
+ mm-serial-port.c \
+ mm-serial-port.h \
+ mm-serial-parsers.c \
+ mm-serial-parsers.h \
+ mm-generic-cdma.c \
+ mm-generic-cdma.h \
+ mm-generic-gsm.c \
+ mm-generic-gsm.h \
mm-modem-cdma.c \
mm-modem-cdma.h \
mm-modem-gsm-card.c \
@@ -37,10 +47,8 @@ modem_manager_SOURCES = \
mm-options.h \
mm-plugin.c \
mm-plugin.h \
- mm-serial.c \
- mm-serial.h \
- mm-serial-parsers.c \
- mm-serial-parsers.h
+ mm-plugin-base.c \
+ mm-plugin-base.h
mm-manager-glue.h: $(top_srcdir)/introspection/mm-manager.xml
dbus-binding-tool --prefix=mm_manager --mode=glib-server --output=$@ $<
diff --git a/src/main.c b/src/main.c
index 629b10ed..36691150 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,21 +1,40 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#include <signal.h>
#include <syslog.h>
#include <string.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
-#include <libhal.h>
#include "mm-manager.h"
#include "mm-options.h"
#define HAL_DBUS_SERVICE "org.freedesktop.Hal"
+static GMainLoop *loop = NULL;
+
static void
mm_signal_handler (int signo)
{
if (signo == SIGUSR1)
mm_options_set_debug (!mm_options_debug ());
+ else if (signo == SIGINT || signo == SIGTERM) {
+ g_message ("Caught signal %d, shutting down...", signo);
+ g_main_loop_quit (loop);
+ }
}
static void
@@ -28,7 +47,9 @@ setup_signals (void)
action.sa_handler = mm_signal_handler;
action.sa_mask = mask;
action.sa_flags = 0;
- sigaction (SIGUSR1, &action, NULL);
+ sigaction (SIGUSR1, &action, NULL);
+ sigaction (SIGTERM, &action, NULL);
+ sigaction (SIGINT, &action, NULL);
}
static void
@@ -89,8 +110,6 @@ logging_shutdown (void)
static void
destroy_cb (DBusGProxy *proxy, gpointer user_data)
{
- GMainLoop *loop = (GMainLoop *) user_data;
-
g_message ("disconnected from the system bus, exiting.");
g_main_loop_quit (loop);
}
@@ -135,87 +154,11 @@ create_dbus_proxy (DBusGConnection *bus)
return proxy;
}
-static void
-hal_init (MMManager *manager)
-{
- LibHalContext *hal_ctx;
- DBusError dbus_error;
-
- hal_ctx = libhal_ctx_new ();
- if (!hal_ctx) {
- g_warning ("Could not get connection to the HAL service.");
- }
-
- libhal_ctx_set_dbus_connection (hal_ctx, dbus_g_connection_get_connection (mm_manager_get_bus (manager)));
-
- dbus_error_init (&dbus_error);
- if (!libhal_ctx_init (hal_ctx, &dbus_error)) {
- g_warning ("libhal_ctx_init() failed: %s", dbus_error.message);
- dbus_error_free (&dbus_error);
- }
-
- mm_manager_set_hal_ctx (manager, hal_ctx);
-}
-
-static void
-hal_deinit (MMManager *manager)
-{
- LibHalContext *hal_ctx;
-
- hal_ctx = mm_manager_get_hal_ctx (manager);
- if (hal_ctx) {
- libhal_ctx_shutdown (hal_ctx, NULL);
- libhal_ctx_free (hal_ctx);
- mm_manager_set_hal_ctx (manager, NULL);
- }
-}
-
static gboolean
-hal_on_bus (DBusGProxy *proxy)
+start_manager (gpointer user_data)
{
- GError *err = NULL;
- gboolean has_owner = FALSE;
-
- if (!dbus_g_proxy_call (proxy,
- "NameHasOwner", &err,
- G_TYPE_STRING, HAL_DBUS_SERVICE,
- G_TYPE_INVALID,
- G_TYPE_BOOLEAN, &has_owner,
- G_TYPE_INVALID)) {
- g_warning ("Error on NameHasOwner DBUS call: %s", err->message);
- g_error_free (err);
- }
-
- return has_owner;
-}
-
-static void
-name_owner_changed (DBusGProxy *proxy,
- const char *name,
- const char *old_owner,
- const char *new_owner,
- gpointer user_data)
-{
- MMManager *manager;
- gboolean old_owner_good;
- gboolean new_owner_good;
-
- /* Only care about signals from HAL */
- if (strcmp (name, HAL_DBUS_SERVICE))
- return;
-
- manager = MM_MANAGER (user_data);
- old_owner_good = (old_owner && (strlen (old_owner) > 0));
- new_owner_good = (new_owner && (strlen (new_owner) > 0));
-
- if (!old_owner_good && new_owner_good) {
- g_message ("HAL appeared");
- hal_init (manager);
- } else if (old_owner_good && !new_owner_good) {
- /* HAL went away. Bad HAL. */
- g_message ("HAL disappeared");
- hal_deinit (manager);
- }
+ mm_manager_start (MM_MANAGER (user_data));
+ return FALSE;
}
int
@@ -223,9 +166,9 @@ main (int argc, char *argv[])
{
DBusGConnection *bus;
DBusGProxy *proxy;
- GMainLoop *loop;
MMManager *manager;
GError *err = NULL;
+ guint id;
mm_options_parse (argc, argv);
g_type_init ();
@@ -249,21 +192,15 @@ main (int argc, char *argv[])
return -1;
manager = mm_manager_new (bus);
-
- dbus_g_proxy_connect_signal (proxy,
- "NameOwnerChanged",
- G_CALLBACK (name_owner_changed),
- manager, NULL);
-
- if (hal_on_bus (proxy))
- hal_init (manager);
+ g_idle_add (start_manager, manager);
loop = g_main_loop_new (NULL, FALSE);
- g_signal_connect (proxy, "destroy", G_CALLBACK (destroy_cb), loop);
+ id = g_signal_connect (proxy, "destroy", G_CALLBACK (destroy_cb), loop);
g_main_loop_run (loop);
- hal_deinit (manager);
+ g_signal_handler_disconnect (proxy, id);
+
g_object_unref (manager);
g_object_unref (proxy);
dbus_g_connection_unref (bus);
diff --git a/src/mm-errors.c b/src/mm-errors.c
index 380ca2f1..e313f0f4 100644
--- a/src/mm-errors.c
+++ b/src/mm-errors.c
@@ -52,7 +52,7 @@ mm_modem_error_get_type (void)
if (etype == 0) {
static const GEnumValue values[] = {
- ENUM_ENTRY (MM_MODEM_ERROR_GENERAL, "Generial"),
+ ENUM_ENTRY (MM_MODEM_ERROR_GENERAL, "General"),
ENUM_ENTRY (MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED, "OperationNotSupported"),
{ 0, 0, 0 }
};
diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c
index de8c916a..7d731384 100644
--- a/src/mm-generic-cdma.c
+++ b/src/mm-generic-cdma.c
@@ -6,6 +6,7 @@
#include "mm-generic-cdma.h"
#include "mm-modem-cdma.h"
#include "mm-modem-simple.h"
+#include "mm-serial-port.h"
#include "mm-errors.h"
#include "mm-callback-info.h"
#include "mm-serial-parsers.h"
@@ -16,25 +17,152 @@ static gpointer mm_generic_cdma_parent_class = NULL;
typedef struct {
char *driver;
+ char *plugin;
+ char *device;
+
+ guint32 ip_method;
+ gboolean valid;
+
+ MMSerialPort *primary;
+ MMSerialPort *secondary;
+ MMPort *data;
} MMGenericCdmaPrivate;
MMModem *
-mm_generic_cdma_new (const char *serial_device, const char *driver)
+mm_generic_cdma_new (const char *device,
+ const char *driver,
+ const char *plugin)
{
- g_return_val_if_fail (serial_device != NULL, NULL);
+ g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
+ g_return_val_if_fail (plugin != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_GENERIC_CDMA,
- MM_SERIAL_DEVICE, serial_device,
+ MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
- MM_MODEM_TYPE, MM_MODEM_TYPE_CDMA,
+ MM_MODEM_PLUGIN, plugin,
NULL));
}
+static const char *
+strip_response (const char *resp, const char *cmd)
+{
+ const char *p = resp;
+
+ if (p) {
+ if (!strncmp (p, cmd, strlen (cmd)))
+ p += strlen (cmd);
+ while (*p == ' ')
+ p++;
+ }
+ return p;
+}
+
/*****************************************************************************/
static void
-enable_error_reporting_done (MMSerial *serial,
+check_valid (MMGenericCdma *self)
+{
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
+ gboolean new_valid = FALSE;
+
+ if (priv->primary && priv->data)
+ new_valid = TRUE;
+
+ if (priv->valid != new_valid) {
+ priv->valid = new_valid;
+ g_object_notify (G_OBJECT (self), MM_MODEM_VALID);
+ }
+}
+
+static gboolean
+owns_port (MMModem *modem, const char *subsys, const char *name)
+{
+ return !!mm_modem_base_get_port (MM_MODEM_BASE (modem), subsys, name);
+}
+
+static gboolean
+grab_port (MMModem *modem,
+ const char *subsys,
+ const char *name,
+ gpointer user_data,
+ GError **error)
+{
+ MMGenericCdma *self = MM_GENERIC_CDMA (modem);
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
+ MMPortType ptype = MM_PORT_TYPE_IGNORED;
+ MMPort *port;
+
+ g_return_val_if_fail (!strcmp (subsys, "net") || !strcmp (subsys, "tty"), FALSE);
+
+ if (!strcmp (subsys, "tty")) {
+ if (!priv->primary)
+ ptype = MM_PORT_TYPE_PRIMARY;
+ else if (!priv->secondary)
+ ptype = MM_PORT_TYPE_SECONDARY;
+ }
+
+ port = mm_modem_base_add_port (MM_MODEM_BASE (self), subsys, name, ptype);
+ if (MM_IS_SERIAL_PORT (port)) {
+ g_object_set (G_OBJECT (port), MM_PORT_CARRIER_DETECT, FALSE, NULL);
+ mm_serial_port_set_response_parser (MM_SERIAL_PORT (port),
+ mm_serial_parser_v1_parse,
+ mm_serial_parser_v1_new (),
+ mm_serial_parser_v1_destroy);
+ }
+
+ if (MM_IS_SERIAL_PORT (port)) {
+ if (ptype == MM_PORT_TYPE_PRIMARY) {
+ priv->primary = MM_SERIAL_PORT (port);
+ if (!priv->data) {
+ priv->data = port;
+ g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE);
+ }
+ check_valid (self);
+ } else if (ptype == MM_PORT_TYPE_SECONDARY)
+ priv->secondary = MM_SERIAL_PORT (port);
+ } else {
+ /* Net device (if any) is the preferred data port */
+ if (!priv->data || MM_IS_SERIAL_PORT (priv->data)) {
+ priv->data = port;
+ g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE);
+ check_valid (self);
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+release_port (MMModem *modem, const char *subsys, const char *name)
+{
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
+ MMPort *port;
+
+ port = mm_modem_base_get_port (MM_MODEM_BASE (modem), subsys, name);
+ if (!port)
+ return;
+
+ if (port == MM_PORT (priv->primary)) {
+ mm_modem_base_remove_port (MM_MODEM_BASE (modem), port);
+ priv->primary = NULL;
+ }
+
+ if (port == priv->data) {
+ priv->data = NULL;
+ g_object_notify (G_OBJECT (modem), MM_MODEM_DATA_DEVICE);
+ }
+
+ if (port == MM_PORT (priv->secondary)) {
+ mm_modem_base_remove_port (MM_MODEM_BASE (modem), port);
+ priv->secondary = NULL;
+ }
+
+ check_valid (MM_GENERIC_CDMA (modem));
+}
+
+static void
+enable_error_reporting_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -49,7 +177,7 @@ enable_error_reporting_done (MMSerial *serial,
}
static void
-init_done (MMSerial *serial,
+init_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -65,14 +193,14 @@ init_done (MMSerial *serial,
FIXME: It's mandatory by spec, so it really shouldn't be optional. Figure
out which CDMA modems have problems with it and implement plugin for them.
*/
- mm_serial_queue_command (serial, "+CMEE=1", 3, enable_error_reporting_done, user_data);
+ mm_serial_port_queue_command (port, "+CMEE=1", 3, enable_error_reporting_done, user_data);
}
}
static void
-flash_done (MMSerial *serial, gpointer user_data)
+flash_done (MMSerialPort *port, gpointer user_data)
{
- mm_serial_queue_command (serial, "Z E0 V1 X4 &C1", 3, init_done, user_data);
+ mm_serial_port_queue_command (port, "Z E0 V1 X4 &C1", 3, init_done, user_data);
}
static void
@@ -81,25 +209,26 @@ enable (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
MMCallbackInfo *info;
info = mm_callback_info_new (modem, callback, user_data);
if (!do_enable) {
- mm_serial_close (MM_SERIAL (modem));
+ mm_serial_port_close (priv->primary);
mm_callback_info_schedule (info);
return;
}
- if (mm_serial_open (MM_SERIAL (modem), &info->error))
- mm_serial_flash (MM_SERIAL (modem), 100, flash_done, info);
+ if (mm_serial_port_open (priv->primary, &info->error))
+ mm_serial_port_flash (priv->primary, 100, flash_done, info);
if (info->error)
mm_callback_info_schedule (info);
}
static void
-dial_done (MMSerial *serial,
+dial_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -118,17 +247,18 @@ connect (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
MMCallbackInfo *info;
char *command;
info = mm_callback_info_new (modem, callback, user_data);
command = g_strconcat ("DT", number, NULL);
- mm_serial_queue_command (MM_SERIAL (modem), command, 60, dial_done, info);
+ mm_serial_port_queue_command (priv->primary, command, 60, dial_done, info);
g_free (command);
}
static void
-disconnect_flash_done (MMSerial *serial, gpointer user_data)
+disconnect_flash_done (MMSerialPort *port, gpointer user_data)
{
mm_callback_info_schedule ((MMCallbackInfo *) user_data);
}
@@ -138,14 +268,99 @@ disconnect (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
MMCallbackInfo *info;
+ g_return_if_fail (priv->primary != NULL);
+
info = mm_callback_info_new (modem, callback, user_data);
- mm_serial_flash (MM_SERIAL (modem), 1000, disconnect_flash_done, info);
+ mm_serial_port_flash (priv->primary, 1000, disconnect_flash_done, info);
+}
+
+static void
+card_info_invoke (MMCallbackInfo *info)
+{
+ MMModemInfoFn callback = (MMModemInfoFn) info->callback;
+
+ callback (info->modem,
+ (char *) mm_callback_info_get_data (info, "card-info-manufacturer"),
+ (char *) mm_callback_info_get_data (info, "card-info-model"),
+ (char *) mm_callback_info_get_data (info, "card-info-version"),
+ info->error, info->user_data);
+}
+
+static void
+get_version_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ const char *p;
+
+ if (!error) {
+ p = strip_response (response->str, "+GMR:");
+ mm_callback_info_set_data (info, "card-info-version", g_strdup (p), g_free);
+ } else if (!info->error)
+ info->error = g_error_copy (error);
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_model_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ const char *p;
+
+ if (!error) {
+ p = strip_response (response->str, "+GMM:");
+ mm_callback_info_set_data (info, "card-info-model", g_strdup (p), g_free);
+ } else if (!info->error)
+ info->error = g_error_copy (error);
+}
+
+static void
+get_manufacturer_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ const char *p;
+
+ if (!error) {
+ p = strip_response (response->str, "+GMI:");
+ mm_callback_info_set_data (info, "card-info-manufacturer", g_strdup (p), g_free);
+ } else
+ info->error = g_error_copy (error);
+}
+
+static void
+get_card_info (MMModem *modem,
+ MMModemInfoFn callback,
+ gpointer user_data)
+{
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new_full (MM_MODEM (modem),
+ card_info_invoke,
+ G_CALLBACK (callback),
+ user_data);
+
+ mm_serial_port_queue_command_cached (priv->primary, "+GMI", 3, get_manufacturer_done, info);
+ mm_serial_port_queue_command_cached (priv->primary, "+GMM", 3, get_model_done, info);
+ mm_serial_port_queue_command_cached (priv->primary, "+GMR", 3, get_version_done, info);
}
+/*****************************************************************************/
+
static void
-get_signal_quality_done (MMSerial *serial,
+get_signal_quality_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -157,18 +372,22 @@ get_signal_quality_done (MMSerial *serial,
info->error = g_error_copy (error);
else if (!strncmp (reply, "+CSQ: ", 6)) {
/* Got valid reply */
- int quality;
- int ber;
+ int quality, ber;
reply += 6;
if (sscanf (reply, "%d,%d", &quality, &ber)) {
- /* 99 means unknown */
- if (quality != 99)
+ /* 99 means unknown/no service */
+ if (quality == 99) {
+ info->error = g_error_new_literal (MM_MOBILE_ERROR,
+ MM_MOBILE_ERROR_NO_NETWORK,
+ "No service");
+ } else {
/* Normalize the quality */
- quality = quality * 100 / 31;
+ quality = CLAMP (quality, 0, 31) * 100 / 31;
- mm_callback_info_set_result (info, GUINT_TO_POINTER (quality), NULL);
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (quality), NULL);
+ }
} else
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
"%s", "Could not parse signal quality results");
@@ -182,10 +401,129 @@ get_signal_quality (MMModemCdma *modem,
MMModemUIntFn callback,
gpointer user_data)
{
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
MMCallbackInfo *info;
info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- mm_serial_queue_command (MM_SERIAL (modem), "+CSQ", 3, get_signal_quality_done, info);
+ /* Prefer secondary port for signal strength */
+ mm_serial_port_queue_command (priv->secondary ? priv->secondary : priv->primary,
+ "+CSQ",
+ 3,
+ get_signal_quality_done, info);
+}
+
+static void
+get_string_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ const char *p;
+
+ if (error)
+ info->error = g_error_copy (error);
+ else {
+ p = strip_response (response->str, "+GSN:");
+ mm_callback_info_set_result (info, g_strdup (p), g_free);
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_esn (MMModemCdma *modem,
+ MMModemStringFn callback,
+ gpointer user_data)
+{
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
+ mm_serial_port_queue_command_cached (priv->primary, "+GSN", 3, get_string_done, info);
+}
+
+static void
+serving_system_invoke (MMCallbackInfo *info)
+{
+ MMModemCdmaServingSystemFn callback = (MMModemCdmaServingSystemFn) info->callback;
+
+ callback (MM_MODEM_CDMA (info->modem),
+ GPOINTER_TO_UINT (mm_callback_info_get_data (info, "class")),
+ (char) GPOINTER_TO_UINT (mm_callback_info_get_data (info, "band")),
+ GPOINTER_TO_UINT (mm_callback_info_get_data (info, "sid")),
+ info->error,
+ info->user_data);
+}
+
+static void
+serving_system_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ char *reply = response->str;
+ int class = 0, sid = 99999, num;
+ char band = 'Z';
+
+ if (error) {
+ info->error = g_error_copy (error);
+ goto out;
+ }
+
+ if (!strstr (reply, "+CSS: ")) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Could not parse Serving System results.");
+ goto out;
+ }
+
+ /* Got valid reply */
+ reply += 6;
+
+ num = sscanf (reply, "%d, %c, %d", &class, &band, &sid);
+ if (num != 3)
+ num = sscanf (reply, "%d,%c,%d", &class, &band, &sid);
+
+ if (num == 3) {
+ /* Normalize */
+ class = CLAMP (class, 0, 4);
+ band = CLAMP (band, 'A', 'Z');
+ if (sid < 0 || sid > 32767)
+ sid = 99999;
+
+ /* 99 means unknown/no service */
+ if (sid == 99999) {
+ info->error = g_error_new_literal (MM_MOBILE_ERROR,
+ MM_MOBILE_ERROR_NO_NETWORK,
+ "No service");
+ } else {
+ mm_callback_info_set_data (info, "class", GUINT_TO_POINTER (class), NULL);
+ mm_callback_info_set_data (info, "band", GUINT_TO_POINTER (band), NULL);
+ mm_callback_info_set_data (info, "sid", GUINT_TO_POINTER (sid), NULL);
+ }
+ } else
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "%s", "Could not parse signal quality results");
+
+ out:
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_serving_system (MMModemCdma *modem,
+ MMModemCdmaServingSystemFn callback,
+ gpointer user_data)
+{
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new_full (MM_MODEM (modem),
+ serving_system_invoke,
+ G_CALLBACK (callback),
+ user_data);
+
+ mm_serial_port_queue_command (priv->primary, "+CSS?", 3, serving_system_done, info);
}
/*****************************************************************************/
@@ -261,6 +599,7 @@ simple_connect (MMModemSimple *simple,
gpointer user_data)
{
MMCallbackInfo *info;
+ GError *error = NULL;
info = mm_callback_info_new (MM_MODEM (simple), callback, user_data);
mm_callback_info_set_data (info, "simple-connect-properties",
@@ -268,12 +607,12 @@ simple_connect (MMModemSimple *simple,
(GDestroyNotify) g_hash_table_unref);
/* At least number must be present */
- if (!simple_get_string_property (info, "number", &info->error)) {
- if (!info->error)
- info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Missing number property");
+ if (!simple_get_string_property (info, "number", &error)) {
+ if (!error)
+ error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Missing number property");
}
- simple_state_machine (MM_MODEM (simple), NULL, info);
+ simple_state_machine (MM_MODEM (simple), error, info);
}
static void
@@ -340,15 +679,21 @@ simple_get_status (MMModemSimple *simple,
static void
modem_init (MMModem *modem_class)
{
+ modem_class->owns_port = owns_port;
+ modem_class->grab_port = grab_port;
+ modem_class->release_port = release_port;
modem_class->enable = enable;
modem_class->connect = connect;
modem_class->disconnect = disconnect;
+ modem_class->get_info = get_card_info;
}
static void
modem_cdma_init (MMModemCdma *cdma_modem_class)
{
cdma_modem_class->get_signal_quality = get_signal_quality;
+ cdma_modem_class->get_esn = get_esn;
+ cdma_modem_class->get_serving_system = get_serving_system;
}
static void
@@ -361,24 +706,32 @@ modem_simple_init (MMModemSimple *class)
static void
mm_generic_cdma_init (MMGenericCdma *self)
{
- mm_serial_set_response_parser (MM_SERIAL (self),
- mm_serial_parser_v1_parse,
- mm_serial_parser_v1_new (),
- mm_serial_parser_v1_destroy);
}
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (object);
+
switch (prop_id) {
case MM_MODEM_PROP_DRIVER:
/* Construct only */
- MM_GENERIC_CDMA_GET_PRIVATE (object)->driver = g_value_dup_string (value);
+ priv->driver = g_value_dup_string (value);
+ break;
+ case MM_MODEM_PROP_PLUGIN:
+ /* Construct only */
+ priv->plugin = g_value_dup_string (value);
+ break;
+ case MM_MODEM_PROP_MASTER_DEVICE:
+ /* Constrcut only */
+ priv->device = g_value_dup_string (value);
break;
- case MM_MODEM_PROP_DEVICE:
- case MM_MODEM_PROP_TYPE:
case MM_MODEM_PROP_IP_METHOD:
+ priv->ip_method = g_value_get_uint (value);
+ break;
+ case MM_MODEM_PROP_TYPE:
+ case MM_MODEM_PROP_VALID:
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -390,18 +743,32 @@ static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (object);
+
switch (prop_id) {
- case MM_MODEM_PROP_DEVICE:
- g_value_set_string (value, mm_serial_get_device (MM_SERIAL (object)));
+ case MM_MODEM_PROP_DATA_DEVICE:
+ if (priv->data)
+ g_value_set_string (value, mm_port_get_device (priv->data));
+ else
+ g_value_set_string (value, NULL);
+ break;
+ case MM_MODEM_PROP_MASTER_DEVICE:
+ g_value_set_string (value, priv->device);
break;
case MM_MODEM_PROP_DRIVER:
- g_value_set_string (value, MM_GENERIC_CDMA_GET_PRIVATE (object)->driver);
+ g_value_set_string (value, priv->driver);
+ break;
+ case MM_MODEM_PROP_PLUGIN:
+ g_value_set_string (value, priv->plugin);
break;
case MM_MODEM_PROP_TYPE:
g_value_set_uint (value, MM_MODEM_TYPE_CDMA);
break;
case MM_MODEM_PROP_IP_METHOD:
- g_value_set_uint (value, MM_MODEM_IP_METHOD_PPP);
+ g_value_set_uint (value, priv->ip_method);
+ break;
+ case MM_MODEM_PROP_VALID:
+ g_value_set_boolean (value, priv->valid);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -434,20 +801,32 @@ mm_generic_cdma_class_init (MMGenericCdmaClass *klass)
/* Properties */
g_object_class_override_property (object_class,
- MM_MODEM_PROP_DEVICE,
- MM_MODEM_DEVICE);
+ MM_MODEM_PROP_DATA_DEVICE,
+ MM_MODEM_DATA_DEVICE);
+
+ g_object_class_override_property (object_class,
+ MM_MODEM_PROP_MASTER_DEVICE,
+ MM_MODEM_MASTER_DEVICE);
g_object_class_override_property (object_class,
MM_MODEM_PROP_DRIVER,
MM_MODEM_DRIVER);
g_object_class_override_property (object_class,
+ MM_MODEM_PROP_PLUGIN,
+ MM_MODEM_PLUGIN);
+
+ g_object_class_override_property (object_class,
MM_MODEM_PROP_TYPE,
MM_MODEM_TYPE);
g_object_class_override_property (object_class,
MM_MODEM_PROP_IP_METHOD,
MM_MODEM_IP_METHOD);
+
+ g_object_class_override_property (object_class,
+ MM_MODEM_PROP_VALID,
+ MM_MODEM_VALID);
}
GType
@@ -480,7 +859,10 @@ mm_generic_cdma_get_type (void)
(GInterfaceInitFunc) modem_simple_init
};
- generic_cdma_type = g_type_register_static (MM_TYPE_SERIAL, "MMGenericCdma", &generic_cdma_type_info, 0);
+ generic_cdma_type = g_type_register_static (MM_TYPE_MODEM_BASE,
+ "MMGenericCdma",
+ &generic_cdma_type_info,
+ 0);
g_type_add_interface_static (generic_cdma_type, MM_TYPE_MODEM, &modem_iface_info);
g_type_add_interface_static (generic_cdma_type, MM_TYPE_MODEM_CDMA, &modem_cdma_iface_info);
diff --git a/src/mm-generic-cdma.h b/src/mm-generic-cdma.h
index 125b540a..44fea73b 100644
--- a/src/mm-generic-cdma.h
+++ b/src/mm-generic-cdma.h
@@ -4,26 +4,27 @@
#define MM_GENERIC_CDMA_H
#include "mm-modem.h"
-#include "mm-serial.h"
+#include "mm-modem-base.h"
-#define MM_TYPE_GENERIC_CDMA (mm_generic_cdma_get_type ())
-#define MM_GENERIC_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_GENERIC_CDMA, MMGenericCdma))
-#define MM_GENERIC_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_GENERIC_CDMA, MMGenericCdmaClass))
-#define MM_IS_GENERIC_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_GENERIC_CDMA))
-#define MM_IS_GENERIC_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_GENERIC_CDMA))
-#define MM_GENERIC_CDMA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_GENERIC_CDMA, MMGenericCdmaClass))
+#define MM_TYPE_GENERIC_CDMA (mm_generic_cdma_get_type ())
+#define MM_GENERIC_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_GENERIC_CDMA, MMGenericCdma))
+#define MM_GENERIC_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_GENERIC_CDMA, MMGenericCdmaClass))
+#define MM_IS_GENERIC_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_GENERIC_CDMA))
+#define MM_IS_GENERIC_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_GENERIC_CDMA))
+#define MM_GENERIC_CDMA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_GENERIC_CDMA, MMGenericCdmaClass))
typedef struct {
- MMSerial parent;
+ MMModemBase parent;
} MMGenericCdma;
typedef struct {
- MMSerialClass parent;
+ MMModemBaseClass parent;
} MMGenericCdmaClass;
GType mm_generic_cdma_get_type (void);
-MMModem *mm_generic_cdma_new (const char *serial_device,
- const char *driver);
+MMModem *mm_generic_cdma_new (const char *device,
+ const char *driver,
+ const char *plugin);
#endif /* MM_GENERIC_CDMA_H */
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index a723a533..06bfff6e 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -18,10 +18,14 @@ static gpointer mm_generic_gsm_parent_class = NULL;
typedef struct {
char *driver;
+ char *plugin;
+ char *device;
+
+ gboolean valid;
+
char *data_device;
char *oper_code;
char *oper_name;
- guint32 modem_type;
guint32 ip_method;
gboolean unsolicited_registration;
@@ -30,24 +34,40 @@ typedef struct {
guint32 signal_quality;
guint32 cid;
+
+ MMSerialPort *primary;
+ MMSerialPort *secondary;
+ MMPort *data;
} MMGenericGsmPrivate;
-static void get_registration_status (MMSerial *serial, MMCallbackInfo *info);
-static void read_operator_done (MMSerial *serial,
- GString *response,
- GError *error,
- gpointer user_data);
+static void get_registration_status (MMSerialPort *port, MMCallbackInfo *info);
+static void read_operator_code_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data);
+
+static void read_operator_name_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data);
+
+static void reg_state_changed (MMSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data);
MMModem *
-mm_generic_gsm_new (const char *serial_device, const char *driver)
+mm_generic_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin)
{
- g_return_val_if_fail (serial_device != NULL, NULL);
+ g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
+ g_return_val_if_fail (plugin != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_GENERIC_GSM,
- MM_SERIAL_DEVICE, serial_device,
+ MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
- MM_MODEM_TYPE, MM_MODEM_TYPE_GSM,
+ MM_MODEM_PLUGIN, plugin,
NULL));
}
@@ -101,8 +121,8 @@ mm_generic_gsm_set_reg_status (MMGenericGsm *modem,
if (status == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
status == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
- mm_serial_queue_command (MM_SERIAL (modem), "+COPS=3,2;+COPS?", 3, read_operator_done, GINT_TO_POINTER (0));
- mm_serial_queue_command (MM_SERIAL (modem), "+COPS=3,0;+COPS?", 3, read_operator_done, GINT_TO_POINTER (1));
+ mm_serial_port_queue_command (priv->primary, "+COPS=3,2;+COPS?", 3, read_operator_code_done, modem);
+ mm_serial_port_queue_command (priv->primary, "+COPS=3,0;+COPS?", 3, read_operator_name_done, modem);
mm_modem_gsm_network_get_signal_quality (MM_MODEM_GSM_NETWORK (modem), got_signal_quality, NULL);
} else {
g_free (priv->oper_code);
@@ -116,7 +136,7 @@ mm_generic_gsm_set_reg_status (MMGenericGsm *modem,
}
static void
-pin_check_done (MMSerial *serial,
+pin_check_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -150,18 +170,138 @@ mm_generic_gsm_check_pin (MMGenericGsm *modem,
MMModemFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv;
MMCallbackInfo *info;
g_return_if_fail (MM_IS_GENERIC_GSM (modem));
+ priv = MM_GENERIC_GSM_GET_PRIVATE (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);
+ mm_serial_port_queue_command (priv->primary, "+CPIN?", 3, pin_check_done, info);
}
/*****************************************************************************/
static void
-enable_done (MMSerial *serial,
+check_valid (MMGenericGsm *self)
+{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ gboolean new_valid = FALSE;
+
+ if (priv->primary && priv->data)
+ new_valid = TRUE;
+
+ if (priv->valid != new_valid) {
+ priv->valid = new_valid;
+ g_object_notify (G_OBJECT (self), MM_MODEM_VALID);
+ }
+}
+
+static gboolean
+owns_port (MMModem *modem, const char *subsys, const char *name)
+{
+ return !!mm_modem_base_get_port (MM_MODEM_BASE (modem), subsys, name);
+}
+
+MMPort *
+mm_generic_gsm_grab_port (MMGenericGsm *self,
+ const char *subsys,
+ const char *name,
+ MMPortType ptype,
+ GError **error)
+{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ MMPort *port = NULL;
+ GRegex *regex;
+
+ g_return_val_if_fail (!strcmp (subsys, "net") || !strcmp (subsys, "tty"), FALSE);
+
+ port = mm_modem_base_add_port (MM_MODEM_BASE (self), subsys, name, ptype);
+ if (MM_IS_SERIAL_PORT (port)) {
+ mm_serial_port_set_response_parser (MM_SERIAL_PORT (port),
+ mm_serial_parser_v1_parse,
+ mm_serial_parser_v1_new (),
+ mm_serial_parser_v1_destroy);
+
+ regex = g_regex_new ("\\r\\n\\+CREG: (\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, reg_state_changed, self, NULL);
+ g_regex_unref (regex);
+
+ if (ptype == MM_PORT_TYPE_PRIMARY) {
+ priv->primary = MM_SERIAL_PORT (port);
+ if (!priv->data) {
+ priv->data = port;
+ g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE);
+ }
+ check_valid (self);
+ } else if (ptype == MM_PORT_TYPE_SECONDARY)
+ priv->secondary = MM_SERIAL_PORT (port);
+ } else {
+ /* Net device (if any) is the preferred data port */
+ if (!priv->data || MM_IS_SERIAL_PORT (priv->data)) {
+ priv->data = port;
+ g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE);
+ check_valid (self);
+ }
+ }
+
+ return port;
+}
+
+static gboolean
+grab_port (MMModem *modem,
+ const char *subsys,
+ const char *name,
+ gpointer user_data,
+ GError **error)
+{
+ MMGenericGsm *self = MM_GENERIC_GSM (modem);
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ MMPortType ptype = MM_PORT_TYPE_IGNORED;
+
+ if (!strcmp (subsys, "tty")) {
+ if (!priv->primary)
+ ptype = MM_PORT_TYPE_PRIMARY;
+ else if (!priv->secondary)
+ ptype = MM_PORT_TYPE_SECONDARY;
+ }
+
+ return !!mm_generic_gsm_grab_port (self, subsys, name, ptype, error);
+}
+
+static void
+release_port (MMModem *modem, const char *subsys, const char *name)
+{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
+ MMPort *port;
+
+ if (strcmp (subsys, "tty"))
+ return;
+
+ port = mm_modem_base_get_port (MM_MODEM_BASE (modem), subsys, name);
+ if (!port)
+ return;
+
+ if (port == MM_PORT (priv->primary)) {
+ mm_modem_base_remove_port (MM_MODEM_BASE (modem), port);
+ priv->primary = NULL;
+ }
+
+ if (port == priv->data) {
+ priv->data = NULL;
+ g_object_notify (G_OBJECT (modem), MM_MODEM_DATA_DEVICE);
+ }
+
+ if (port == MM_PORT (priv->secondary)) {
+ mm_modem_base_remove_port (MM_MODEM_BASE (modem), port);
+ priv->secondary = NULL;
+ }
+
+ check_valid (MM_GENERIC_GSM (modem));
+}
+
+static void
+enable_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -175,46 +315,65 @@ enable_done (MMSerial *serial,
}
static void
-init_done (MMSerial *serial,
+init_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ char *cmd = NULL;
if (error) {
info->error = g_error_copy (error);
mm_callback_info_schedule (info);
} else {
- if (MM_GENERIC_GSM_GET_PRIVATE (serial)->unsolicited_registration)
- mm_serial_queue_command (serial, "+CREG=1", 5, NULL, NULL);
+ if (MM_GENERIC_GSM_GET_PRIVATE (info->modem)->unsolicited_registration)
+ mm_serial_port_queue_command (port, "+CREG=1", 5, NULL, NULL);
else
- mm_serial_queue_command (serial, "+CREG=0", 5, NULL, NULL);
+ mm_serial_port_queue_command (port, "+CREG=0", 5, NULL, NULL);
- mm_serial_queue_command (serial, "+CFUN=1", 5, enable_done, user_data);
+ g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_POWER_UP_CMD, &cmd, NULL);
+ if (cmd && strlen (cmd))
+ mm_serial_port_queue_command (port, cmd, 5, enable_done, user_data);
+ else
+ enable_done (port, NULL, NULL, user_data);
+ g_free (cmd);
}
}
static void
-enable_flash_done (MMSerial *serial, gpointer user_data)
+enable_flash_done (MMSerialPort *port, gpointer user_data)
{
- mm_serial_queue_command (serial, "Z E0 V1 X4 &C1 +CMEE=1", 3, init_done, user_data);
+ MMCallbackInfo *info = user_data;
+ char *cmd = NULL;
+
+ g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_INIT_CMD, &cmd, NULL);
+ mm_serial_port_queue_command (port, cmd, 3, init_done, user_data);
+ g_free (cmd);
}
static void
-disable_done (MMSerial *serial,
+disable_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
- mm_serial_close (serial);
+ mm_serial_port_close (port);
mm_callback_info_schedule ((MMCallbackInfo *) user_data);
}
static void
-disable_flash_done (MMSerial *serial, gpointer user_data)
+disable_flash_done (MMSerialPort *port, gpointer user_data)
{
- mm_serial_queue_command (serial, "+CFUN=0", 5, disable_done, user_data);
+ MMCallbackInfo *info = user_data;
+ char *cmd = NULL;
+
+ g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_POWER_UP_CMD, &cmd, NULL);
+ if (cmd && strlen (cmd))
+ mm_serial_port_queue_command (port, cmd, 5, disable_done, user_data);
+ else
+ disable_done (port, NULL, NULL, user_data);
+ g_free (cmd);
}
static void
@@ -223,6 +382,7 @@ enable (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
/* First, reset the previously used CID */
@@ -233,13 +393,13 @@ enable (MMModem *modem,
if (!do_enable) {
mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (modem));
- if (mm_serial_is_connected (MM_SERIAL (modem)))
- mm_serial_flash (MM_SERIAL (modem), 1000, disable_flash_done, info);
+ if (mm_serial_port_is_connected (priv->primary))
+ mm_serial_port_flash (priv->primary, 1000, disable_flash_done, info);
else
- disable_flash_done (MM_SERIAL (modem), info);
+ disable_flash_done (priv->primary, info);
} else {
- if (mm_serial_open (MM_SERIAL (modem), &info->error))
- mm_serial_flash (MM_SERIAL (modem), 100, enable_flash_done, info);
+ if (mm_serial_port_open (priv->primary, &info->error))
+ mm_serial_port_flash (priv->primary, 100, enable_flash_done, info);
if (info->error)
mm_callback_info_schedule (info);
@@ -247,7 +407,7 @@ enable (MMModem *modem,
}
static void
-get_string_done (MMSerial *serial,
+get_string_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -267,10 +427,11 @@ get_imei (MMModemGsmCard *modem,
MMModemStringFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
- mm_serial_queue_command_cached (MM_SERIAL (modem), "+CGSN", 3, get_string_done, info);
+ mm_serial_port_queue_command_cached (priv->primary, "+CGSN", 3, get_string_done, info);
}
static void
@@ -278,18 +439,19 @@ get_imsi (MMModemGsmCard *modem,
MMModemStringFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
- mm_serial_queue_command_cached (MM_SERIAL (modem), "+CIMI", 3, get_string_done, info);
+ mm_serial_port_queue_command_cached (priv->primary, "+CIMI", 3, get_string_done, info);
}
static void
-gsm_card_info_invoke (MMCallbackInfo *info)
+card_info_invoke (MMCallbackInfo *info)
{
- MMModemGsmCardInfoFn callback = (MMModemGsmCardInfoFn) info->callback;
+ MMModemInfoFn callback = (MMModemInfoFn) info->callback;
- callback (MM_MODEM_GSM_CARD (info->modem),
+ callback (info->modem,
(char *) mm_callback_info_get_data (info, "card-info-manufacturer"),
(char *) mm_callback_info_get_data (info, "card-info-model"),
(char *) mm_callback_info_get_data (info, "card-info-version"),
@@ -297,7 +459,7 @@ gsm_card_info_invoke (MMCallbackInfo *info)
}
static void
-get_version_done (MMSerial *serial,
+get_version_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -313,7 +475,7 @@ get_version_done (MMSerial *serial,
}
static void
-get_model_done (MMSerial *serial,
+get_model_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -327,7 +489,7 @@ get_model_done (MMSerial *serial,
}
static void
-get_manufacturer_done (MMSerial *serial,
+get_manufacturer_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -341,25 +503,25 @@ get_manufacturer_done (MMSerial *serial,
}
static void
-get_card_info (MMModemGsmCard *modem,
- MMModemGsmCardInfoFn callback,
+get_card_info (MMModem *modem,
+ MMModemInfoFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
- MMSerial *serial = MM_SERIAL (modem);
info = mm_callback_info_new_full (MM_MODEM (modem),
- gsm_card_info_invoke,
+ card_info_invoke,
G_CALLBACK (callback),
user_data);
- mm_serial_queue_command_cached (serial, "+CGMI", 3, get_manufacturer_done, info);
- mm_serial_queue_command_cached (serial, "+CGMM", 3, get_model_done, info);
- mm_serial_queue_command_cached (serial, "+CGMR", 3, get_version_done, info);
+ mm_serial_port_queue_command_cached (priv->primary, "+CGMI", 3, get_manufacturer_done, info);
+ mm_serial_port_queue_command_cached (priv->primary, "+CGMM", 3, get_model_done, info);
+ mm_serial_port_queue_command_cached (priv->primary, "+CGMR", 3, get_version_done, info);
}
static void
-send_puk_done (MMSerial *serial,
+send_puk_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -378,17 +540,18 @@ send_puk (MMModemGsmCard *modem,
MMModemFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
char *command;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
command = g_strdup_printf ("+CPIN=\"%s\",\"%s\"", puk, pin);
- mm_serial_queue_command (MM_SERIAL (modem), command, 3, send_puk_done, info);
+ mm_serial_port_queue_command (priv->primary, command, 3, send_puk_done, info);
g_free (command);
}
static void
-send_pin_done (MMSerial *serial,
+send_pin_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -406,17 +569,18 @@ send_pin (MMModemGsmCard *modem,
MMModemFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
char *command;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
command = g_strdup_printf ("+CPIN=\"%s\"", pin);
- mm_serial_queue_command (MM_SERIAL (modem), command, 3, send_pin_done, info);
+ mm_serial_port_queue_command (priv->primary, command, 3, send_pin_done, info);
g_free (command);
}
static void
-enable_pin_done (MMSerial *serial,
+enable_pin_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -435,17 +599,18 @@ enable_pin (MMModemGsmCard *modem,
MMModemFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
char *command;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
command = g_strdup_printf ("+CLCK=\"SC\",%d,\"%s\"", enabled ? 1 : 0, pin);
- mm_serial_queue_command (MM_SERIAL (modem), command, 3, enable_pin_done, info);
+ mm_serial_port_queue_command (priv->primary, command, 3, enable_pin_done, info);
g_free (command);
}
static void
-change_pin_done (MMSerial *serial,
+change_pin_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -464,12 +629,13 @@ change_pin (MMModemGsmCard *modem,
MMModemFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
char *command;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
command = g_strdup_printf ("+CPWD=\"SC\",\"%s\",\"%s\"", old_pin, new_pin);
- mm_serial_queue_command (MM_SERIAL (modem), command, 3, change_pin_done, info);
+ mm_serial_port_queue_command (priv->primary, command, 3, change_pin_done, info);
g_free (command);
}
@@ -500,30 +666,48 @@ parse_operator (const char *reply)
}
static void
-read_operator_done (MMSerial *serial,
- GString *response,
- GError *error,
- gpointer user_data)
+read_operator_code_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
- if (!error) {
- char *oper;
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (user_data);
+ char *oper;
- oper = parse_operator (response->str);
- if (oper) {
- MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (serial);
+ if (error)
+ return;
- if (GPOINTER_TO_INT (user_data) == 0) {
- g_free (priv->oper_code);
- priv->oper_code = oper;
- } else {
- g_free (priv->oper_name);
- priv->oper_name = oper;
+ oper = parse_operator (response->str);
+ if (!oper)
+ return;
- mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (serial), priv->reg_status,
- priv->oper_code, priv->oper_name);
- }
- }
- }
+ g_free (priv->oper_code);
+ priv->oper_code = oper;
+}
+
+static void
+read_operator_name_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (user_data);
+ char *oper;
+
+ if (error)
+ return;
+
+ oper = parse_operator (response->str);
+ if (!oper)
+ return;
+
+ g_free (priv->oper_name);
+ priv->oper_name = oper;
+
+ mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (user_data),
+ priv->reg_status,
+ priv->oper_code,
+ priv->oper_name);
}
/* Registration */
@@ -579,24 +763,27 @@ reg_status_updated (MMGenericGsm *self, int new_value)
}
static void
-reg_state_changed (MMSerial *serial,
+reg_state_changed (MMSerialPort *port,
GMatchInfo *match_info,
gpointer user_data)
{
+ MMGenericGsm *self = MM_GENERIC_GSM (user_data);
char *str;
str = g_match_info_fetch (match_info, 1);
- reg_status_updated (MM_GENERIC_GSM (serial), atoi (str));
+ reg_status_updated (self, atoi (str));
g_free (str);
}
static gboolean
reg_status_again (gpointer data)
{
+ MMGenericGsmPrivate *priv;
MMCallbackInfo *info = (MMCallbackInfo *) data;
- if (MM_GENERIC_GSM_GET_PRIVATE (info->modem)->pending_reg_id)
- get_registration_status (MM_SERIAL (info->modem), info);
+ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
+ if (priv->pending_reg_id)
+ get_registration_status (priv->primary, info);
return FALSE;
}
@@ -608,13 +795,13 @@ reg_status_again_remove (gpointer data)
}
static void
-get_reg_status_done (MMSerial *serial,
+get_reg_status_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMGenericGsm *self = MM_GENERIC_GSM (serial);
+ MMGenericGsm *self = MM_GENERIC_GSM (info->modem);
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
int unsolicited, stat;
guint id;
@@ -637,7 +824,7 @@ get_reg_status_done (MMSerial *serial,
return;
}
- reg_status_updated (MM_GENERIC_GSM (serial), stat);
+ reg_status_updated (self, stat);
if (priv->pending_reg_id) {
/* Registration is still going */
@@ -673,19 +860,19 @@ get_reg_status_done (MMSerial *serial,
}
static void
-get_registration_status (MMSerial *serial, MMCallbackInfo *info)
+get_registration_status (MMSerialPort *port, MMCallbackInfo *info)
{
- mm_serial_queue_command (serial, "+CREG?", 3, get_reg_status_done, info);
+ mm_serial_port_queue_command (port, "+CREG?", 3, get_reg_status_done, info);
}
static void
-register_done (MMSerial *serial,
+register_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
/* Ignore errors here, get the actual registration status */
- get_registration_status (serial, (MMCallbackInfo *) user_data);
+ get_registration_status (port, (MMCallbackInfo *) user_data);
}
static gboolean
@@ -708,8 +895,8 @@ do_register (MMModemGsmNetwork *modem,
MMModemFn callback,
gpointer user_data)
{
- MMCallbackInfo *info;
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
+ MMCallbackInfo *info;
char *command;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
@@ -721,7 +908,7 @@ do_register (MMModemGsmNetwork *modem,
else
command = g_strdup ("+COPS=0,,");
- mm_serial_queue_command (MM_SERIAL (modem), command, 10, register_done, info);
+ mm_serial_port_queue_command (priv->primary, command, 10, register_done, info);
g_free (command);
}
@@ -755,7 +942,7 @@ get_registration_info (MMModemGsmNetwork *self,
}
static void
-connect_report_done (MMSerial *serial,
+connect_report_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -771,17 +958,19 @@ connect_report_done (MMSerial *serial,
}
static void
-connect_done (MMSerial *serial,
+connect_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv;
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
if (error) {
info->error = g_error_copy (error);
/* Try to get more information why it failed */
- mm_serial_queue_command (serial, "+CEER", 3, connect_report_done, info);
+ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
+ mm_serial_port_queue_command (priv->primary, "+CEER", 3, connect_report_done, info);
} else
/* Done */
mm_callback_info_schedule (info);
@@ -793,6 +982,7 @@ connect (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
char *command;
guint32 cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (modem));
@@ -813,12 +1003,12 @@ connect (MMModem *modem,
} else
command = g_strconcat ("DT", number, NULL);
- mm_serial_queue_command (MM_SERIAL (modem), command, 60, connect_done, info);
+ mm_serial_port_queue_command (priv->primary, command, 60, connect_done, info);
g_free (command);
}
static void
-disconnect_flash_done (MMSerial *serial, gpointer user_data)
+disconnect_flash_done (MMSerialPort *port, gpointer user_data)
{
mm_callback_info_schedule ((MMCallbackInfo *) user_data);
}
@@ -828,13 +1018,14 @@ disconnect (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
/* First, reset the previously used CID */
mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0);
info = mm_callback_info_new (modem, callback, user_data);
- mm_serial_flash (MM_SERIAL (modem), 1000, disconnect_flash_done, info);
+ mm_serial_port_flash (priv->primary, 1000, disconnect_flash_done, info);
}
static void
@@ -858,7 +1049,7 @@ destroy_scan_data (gpointer data)
}
static void
-scan_done (MMSerial *serial,
+scan_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -868,17 +1059,27 @@ scan_done (MMSerial *serial,
if (error)
info->error = g_error_copy (error);
- else if (!strncmp (reply, "+COPS: ", 7)) {
+ else if (strstr (reply, "+COPS: ")) {
/* Got valid reply */
GPtrArray *results;
GRegex *r;
GMatchInfo *match_info;
GError *err = NULL;
- reply += 7;
+ reply = strstr (reply, "+COPS: ") + 7;
- /* Pattern without crazy escaping using | for matching: (|\d|,"|.+|","|.+|","|.+|",|\d|) */
- r = g_regex_new ("\\((\\d),\"(.*)\",\"(.*)\",\"(.*)\",(\\d)\\)", G_REGEX_UNGREEDY, 0, &err);
+ /* Pattern without crazy escaping using | for matching: (|\d|,"|.+|","|.+|","|.+|"\)?,|\d|) */
+
+ /* Quirk: Sony-Ericsson TM-506 sometimes includes a stray ')' like so:
+ *
+ * +COPS: (2,"","T-Mobile","31026",0),(1,"AT&T","AT&T","310410"),0)
+ *
+ * Quirk: Motorola C-series (BUSlink SCWi275u) don't include the operator
+ * number, like so:
+ *
+ * +COPS: (2,"T-Mobile","","310260"),(0,"Cingular Wireless","","310410")
+ */
+ r = g_regex_new ("\\((\\d),\"(.*)\",\"(.*)\",\"(.*)\"\\)?[,]?[(\\d)]?\\)", G_REGEX_UNGREEDY, 0, &err);
if (err) {
g_error ("Invalid regular expression: %s", err->message);
g_error_free (err);
@@ -919,6 +1120,7 @@ scan (MMModemGsmNetwork *modem,
MMModemGsmNetworkScanFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
info = mm_callback_info_new_full (MM_MODEM (modem),
@@ -926,13 +1128,13 @@ scan (MMModemGsmNetwork *modem,
G_CALLBACK (callback),
user_data);
- mm_serial_queue_command (MM_SERIAL (modem), "+COPS=?", 60, scan_done, info);
+ mm_serial_port_queue_command (priv->primary, "+COPS=?", 60, scan_done, info);
}
/* SetApn */
static void
-set_apn_done (MMSerial *serial,
+set_apn_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -942,14 +1144,14 @@ set_apn_done (MMSerial *serial,
if (error)
info->error = g_error_copy (error);
else
- mm_generic_gsm_set_cid (MM_GENERIC_GSM (serial),
+ mm_generic_gsm_set_cid (MM_GENERIC_GSM (info->modem),
GPOINTER_TO_UINT (mm_callback_info_get_data (info, "cid")));
mm_callback_info_schedule (info);
}
static void
-cid_range_read (MMSerial *serial,
+cid_range_read (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -1009,13 +1211,13 @@ cid_range_read (MMSerial *serial,
mm_callback_info_set_data (info, "cid", GUINT_TO_POINTER (cid), NULL);
command = g_strdup_printf ("+CGDCONT=%d, \"IP\", \"%s\"", cid, apn);
- mm_serial_queue_command (serial, command, 3, set_apn_done, info);
+ mm_serial_port_queue_command (port, command, 3, set_apn_done, info);
g_free (command);
}
}
static void
-existing_apns_read (MMSerial *serial,
+existing_apns_read (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -1048,7 +1250,7 @@ existing_apns_read (MMSerial *serial,
apn = g_match_info_fetch (match_info, 3);
if (!strcmp (apn, new_apn)) {
- mm_generic_gsm_set_cid (MM_GENERIC_GSM (serial), (guint32) num_cid);
+ mm_generic_gsm_set_cid (MM_GENERIC_GSM (info->modem), (guint32) num_cid);
found = TRUE;
}
@@ -1080,7 +1282,7 @@ existing_apns_read (MMSerial *serial,
mm_callback_info_schedule (info);
else
/* APN not configured on the card. Get the allowed CID range */
- mm_serial_queue_command_cached (serial, "+CGDCONT=?", 3, cid_range_read, info);
+ mm_serial_port_queue_command_cached (port, "+CGDCONT=?", 3, cid_range_read, info);
}
static void
@@ -1089,23 +1291,25 @@ set_apn (MMModemGsmNetwork *modem,
MMModemFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
mm_callback_info_set_data (info, "apn", g_strdup (apn), g_free);
/* Start by searching if the APN is already in card */
- mm_serial_queue_command (MM_SERIAL (modem), "+CGDCONT?", 3, existing_apns_read, info);
+ mm_serial_port_queue_command (priv->primary, "+CGDCONT?", 3, existing_apns_read, info);
}
/* GetSignalQuality */
static void
-get_signal_quality_done (MMSerial *serial,
+get_signal_quality_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv;
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
char *reply = response->str;
@@ -1124,7 +1328,8 @@ get_signal_quality_done (MMSerial *serial,
/* Normalize the quality */
quality = quality * 100 / 31;
- MM_GENERIC_GSM_GET_PRIVATE (serial)->signal_quality = quality;
+ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
+ priv->signal_quality = quality;
mm_callback_info_set_result (info, GUINT_TO_POINTER (quality), NULL);
} else
info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
@@ -1139,23 +1344,26 @@ get_signal_quality (MMModemGsmNetwork *modem,
MMModemUIntFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
+ gboolean connected;
- if (mm_serial_is_connected (MM_SERIAL (modem))) {
- g_message ("Returning saved signal quality %d", MM_GENERIC_GSM_GET_PRIVATE (modem)->signal_quality);
- callback (MM_MODEM (modem), MM_GENERIC_GSM_GET_PRIVATE (modem)->signal_quality, NULL, user_data);
+ connected = mm_serial_port_is_connected (priv->primary);
+ if (connected && !priv->secondary) {
+ g_message ("Returning saved signal quality %d", priv->signal_quality);
+ callback (MM_MODEM (modem), priv->signal_quality, NULL, user_data);
return;
}
info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- mm_serial_queue_command (MM_SERIAL (modem), "+CSQ", 3, get_signal_quality_done, info);
+ mm_serial_port_queue_command (connected ? priv->secondary : priv->primary, "+CSQ", 3, get_signal_quality_done, info);
}
/*****************************************************************************/
/* MMModemGsmSms interface */
static void
-sms_send_done (MMSerial *serial,
+sms_send_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -1178,19 +1386,51 @@ sms_send (MMModemGsmSms *modem,
MMModemFn callback,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv;
MMCallbackInfo *info;
char *command;
+ gboolean connected;
+ MMSerialPort *port = NULL;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
+ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
+ connected = mm_serial_port_is_connected (priv->primary);
+ if (connected)
+ port = priv->secondary;
+ else
+ port = priv->primary;
+
+ if (!port) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Cannot send SMS while connected");
+ mm_callback_info_schedule (info);
+ return;
+ }
+
/* FIXME: use the PDU mode instead */
- mm_serial_queue_command (MM_SERIAL (modem), "AT+CMGF=1", 3, NULL, NULL);
+ mm_serial_port_queue_command (port, "AT+CMGF=1", 3, NULL, NULL);
command = g_strdup_printf ("+CMGS=\"%s\"\r%s\x1a", number, text);
- mm_serial_queue_command (MM_SERIAL (modem), command, 10, sms_send_done, info);
+ mm_serial_port_queue_command (port, command, 10, sms_send_done, info);
g_free (command);
}
+MMSerialPort *
+mm_generic_gsm_get_port (MMGenericGsm *modem,
+ MMPortType ptype)
+{
+ g_return_val_if_fail (MM_IS_GENERIC_GSM (modem), NULL);
+ g_return_val_if_fail (ptype != MM_PORT_TYPE_UNKNOWN, NULL);
+
+ if (ptype == MM_PORT_TYPE_PRIMARY)
+ return MM_GENERIC_GSM_GET_PRIVATE (modem)->primary;
+ else if (ptype == MM_PORT_TYPE_SECONDARY)
+ return MM_GENERIC_GSM_GET_PRIVATE (modem)->secondary;
+
+ return NULL;
+}
+
/*****************************************************************************/
/* MMModemSimple interface */
@@ -1438,9 +1678,13 @@ simple_get_status (MMModemSimple *simple,
static void
modem_init (MMModem *modem_class)
{
+ modem_class->owns_port = owns_port;
+ modem_class->grab_port = grab_port;
+ modem_class->release_port = release_port;
modem_class->enable = enable;
modem_class->connect = connect;
modem_class->disconnect = disconnect;
+ modem_class->get_info = get_card_info;
}
static void
@@ -1448,7 +1692,6 @@ modem_gsm_card_init (MMModemGsmCard *class)
{
class->get_imei = get_imei;
class->get_imsi = get_imsi;
- class->get_info = get_card_info;
class->send_pin = send_pin;
class->send_puk = send_puk;
class->enable_pin = enable_pin;
@@ -1481,16 +1724,6 @@ modem_simple_init (MMModemSimple *class)
static void
mm_generic_gsm_init (MMGenericGsm *self)
{
- GRegex *regex;
-
- mm_serial_set_response_parser (MM_SERIAL (self),
- mm_serial_parser_v1_parse,
- mm_serial_parser_v1_new (),
- mm_serial_parser_v1_destroy);
-
- regex = g_regex_new ("\\r\\n\\+CREG: (\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_add_unsolicited_msg_handler (MM_SERIAL (self), regex, reg_state_changed, NULL, NULL);
- g_regex_unref (regex);
}
static void
@@ -1504,16 +1737,23 @@ set_property (GObject *object, guint prop_id,
/* Construct only */
priv->driver = g_value_dup_string (value);
break;
- case MM_MODEM_PROP_DEVICE:
- g_free (priv->data_device);
- priv->data_device = g_value_dup_string (value);
+ case MM_MODEM_PROP_PLUGIN:
+ /* Construct only */
+ priv->plugin = g_value_dup_string (value);
break;
- case MM_MODEM_PROP_TYPE:
- priv->modem_type = g_value_get_uint (value);
+ case MM_MODEM_PROP_MASTER_DEVICE:
+ /* Constrcut only */
+ priv->device = g_value_dup_string (value);
break;
case MM_MODEM_PROP_IP_METHOD:
priv->ip_method = g_value_get_uint (value);
break;
+ case MM_MODEM_PROP_TYPE:
+ case MM_MODEM_PROP_VALID:
+ case MM_GENERIC_GSM_PROP_POWER_UP_CMD:
+ case MM_GENERIC_GSM_PROP_POWER_DOWN_CMD:
+ case MM_GENERIC_GSM_PROP_INIT_CMD:
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1527,21 +1767,39 @@ get_property (GObject *object, guint prop_id,
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (object);
switch (prop_id) {
- case MM_MODEM_PROP_DEVICE:
- if (priv->data_device)
- g_value_set_string (value, priv->data_device);
+ case MM_MODEM_PROP_DATA_DEVICE:
+ if (priv->data)
+ g_value_set_string (value, mm_port_get_device (priv->data));
else
- g_value_set_string (value, mm_serial_get_device (MM_SERIAL (object)));
+ g_value_set_string (value, NULL);
+ break;
+ case MM_MODEM_PROP_MASTER_DEVICE:
+ g_value_set_string (value, priv->device);
break;
case MM_MODEM_PROP_DRIVER:
- g_value_set_string (value, MM_GENERIC_GSM_GET_PRIVATE (object)->driver);
+ g_value_set_string (value, priv->driver);
+ break;
+ case MM_MODEM_PROP_PLUGIN:
+ g_value_set_string (value, priv->plugin);
break;
case MM_MODEM_PROP_TYPE:
- g_value_set_uint (value, priv->modem_type);
+ g_value_set_uint (value, MM_MODEM_TYPE_GSM);
break;
case MM_MODEM_PROP_IP_METHOD:
g_value_set_uint (value, priv->ip_method);
break;
+ case MM_MODEM_PROP_VALID:
+ g_value_set_boolean (value, priv->valid);
+ break;
+ case MM_GENERIC_GSM_PROP_POWER_UP_CMD:
+ g_value_set_string (value, "+CFUN=1");
+ break;
+ case MM_GENERIC_GSM_PROP_POWER_DOWN_CMD:
+ g_value_set_string (value, "+CFUN=0");
+ break;
+ case MM_GENERIC_GSM_PROP_INIT_CMD:
+ g_value_set_string (value, "Z E0 V1 X4 &C1 +CMEE=1");
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1578,14 +1836,22 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass)
/* Properties */
g_object_class_override_property (object_class,
- MM_MODEM_PROP_DEVICE,
- MM_MODEM_DEVICE);
+ MM_MODEM_PROP_DATA_DEVICE,
+ MM_MODEM_DATA_DEVICE);
+
+ g_object_class_override_property (object_class,
+ MM_MODEM_PROP_MASTER_DEVICE,
+ MM_MODEM_MASTER_DEVICE);
g_object_class_override_property (object_class,
MM_MODEM_PROP_DRIVER,
MM_MODEM_DRIVER);
g_object_class_override_property (object_class,
+ MM_MODEM_PROP_PLUGIN,
+ MM_MODEM_PLUGIN);
+
+ g_object_class_override_property (object_class,
MM_MODEM_PROP_TYPE,
MM_MODEM_TYPE);
@@ -1593,6 +1859,33 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass)
MM_MODEM_PROP_IP_METHOD,
MM_MODEM_IP_METHOD);
+ g_object_class_override_property (object_class,
+ MM_MODEM_PROP_VALID,
+ MM_MODEM_VALID);
+
+ g_object_class_install_property
+ (object_class, MM_GENERIC_GSM_PROP_POWER_UP_CMD,
+ g_param_spec_string (MM_GENERIC_GSM_POWER_UP_CMD,
+ "PowerUpCommand",
+ "Power up command",
+ "+CFUN=1",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property
+ (object_class, MM_GENERIC_GSM_PROP_POWER_DOWN_CMD,
+ g_param_spec_string (MM_GENERIC_GSM_POWER_DOWN_CMD,
+ "PowerDownCommand",
+ "Power down command",
+ "+CFUN=0",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property
+ (object_class, MM_GENERIC_GSM_PROP_INIT_CMD,
+ g_param_spec_string (MM_GENERIC_GSM_INIT_CMD,
+ "InitCommand",
+ "Initialization command",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
GType
@@ -1633,7 +1926,10 @@ mm_generic_gsm_get_type (void)
(GInterfaceInitFunc) modem_simple_init
};
- generic_gsm_type = g_type_register_static (MM_TYPE_SERIAL, "MMGenericGsm", &generic_gsm_type_info, 0);
+ generic_gsm_type = g_type_register_static (MM_TYPE_MODEM_BASE,
+ "MMGenericGsm",
+ &generic_gsm_type_info,
+ 0);
g_type_add_interface_static (generic_gsm_type, MM_TYPE_MODEM, &modem_iface_info);
g_type_add_interface_static (generic_gsm_type, MM_TYPE_MODEM_GSM_CARD, &modem_gsm_card_info);
diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h
index 3f857365..bd0af4ba 100644
--- a/src/mm-generic-gsm.h
+++ b/src/mm-generic-gsm.h
@@ -4,27 +4,44 @@
#define MM_GENERIC_GSM_H
#include "mm-modem-gsm-network.h"
-#include "mm-serial.h"
+#include "mm-modem-base.h"
+#include "mm-serial-port.h"
+
+#define MM_TYPE_GENERIC_GSM (mm_generic_gsm_get_type ())
+#define MM_GENERIC_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_GENERIC_GSM, MMGenericGsm))
+#define MM_GENERIC_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_GENERIC_GSM, MMGenericGsmClass))
+#define MM_IS_GENERIC_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_GENERIC_GSM))
+#define MM_IS_GENERIC_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_GENERIC_GSM))
+#define MM_GENERIC_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_GENERIC_GSM, MMGenericGsmClass))
+
+#define MM_GENERIC_GSM_POWER_UP_CMD "power-up-cmd"
+#define MM_GENERIC_GSM_POWER_DOWN_CMD "power-down-cmd"
+#define MM_GENERIC_GSM_INIT_CMD "init-cmd"
+
+typedef enum {
+ MM_GENERIC_GSM_PROP_FIRST = 0x2000,
+
+ MM_GENERIC_GSM_PROP_POWER_UP_CMD,
+ MM_GENERIC_GSM_PROP_POWER_DOWN_CMD,
+ MM_GENERIC_GSM_PROP_INIT_CMD,
+
+ MM_GENERIC_GSM_LAST_PROP = MM_GENERIC_GSM_PROP_POWER_DOWN_CMD
+} MMGenericGsmProp;
-#define MM_TYPE_GENERIC_GSM (mm_generic_gsm_get_type ())
-#define MM_GENERIC_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_GENERIC_GSM, MMGenericGsm))
-#define MM_GENERIC_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_GENERIC_GSM, MMGenericGsmClass))
-#define MM_IS_GENERIC_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_GENERIC_GSM))
-#define MM_IS_GENERIC_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_GENERIC_GSM))
-#define MM_GENERIC_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_GENERIC_GSM, MMGenericGsmClass))
typedef struct {
- MMSerial parent;
+ MMModemBase parent;
} MMGenericGsm;
typedef struct {
- MMSerialClass parent;
+ MMModemBaseClass parent;
} MMGenericGsmClass;
GType mm_generic_gsm_get_type (void);
-MMModem *mm_generic_gsm_new (const char *serial_device,
- const char *driver);
+MMModem *mm_generic_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin);
void mm_generic_gsm_set_unsolicited_registration (MMGenericGsm *modem,
gboolean enabled);
@@ -42,4 +59,13 @@ void mm_generic_gsm_check_pin (MMGenericGsm *modem,
MMModemFn callback,
gpointer user_data);
+MMSerialPort *mm_generic_gsm_get_port (MMGenericGsm *modem,
+ MMPortType ptype);
+
+MMPort *mm_generic_gsm_grab_port (MMGenericGsm *modem,
+ const char *subsys,
+ const char *name,
+ MMPortType ptype,
+ GError **error);
+
#endif /* MM_GENERIC_GSM_H */
diff --git a/src/mm-manager.c b/src/mm-manager.c
index a19c9446..aa109a99 100644
--- a/src/mm-manager.c
+++ b/src/mm-manager.c
@@ -2,12 +2,12 @@
#include <string.h>
#include <gmodule.h>
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include "mm-manager.h"
#include "mm-errors.h"
-#include "mm-generic-gsm.h"
-#include "mm-generic-cdma.h"
#include "mm-plugin.h"
static gboolean impl_manager_enumerate_devices (MMManager *manager,
@@ -29,11 +29,15 @@ static guint signals[LAST_SIGNAL] = { 0 };
#define MM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MANAGER, MMManagerPrivate))
+#define DBUS_PATH_TAG "dbus-path"
+
typedef struct {
DBusGConnection *connection;
- LibHalContext *hal_ctx;
+ GUdevClient *udev;
GSList *plugins;
GHashTable *modems;
+
+ GHashTable *supports;
} MMManagerPrivate;
static MMPlugin *
@@ -97,6 +101,7 @@ load_plugins (MMManager *manager)
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
GDir *dir;
const char *fname;
+ MMPlugin *generic_plugin = NULL;
if (!g_module_supported ()) {
g_warning ("GModules are not supported on your platform!");
@@ -120,10 +125,18 @@ load_plugins (MMManager *manager)
plugin = load_plugin (path);
g_free (path);
- if (plugin)
- priv->plugins = g_slist_append (priv->plugins, plugin);
+ if (plugin) {
+ if (!strcmp (mm_plugin_get_name (plugin), MM_PLUGIN_GENERIC_NAME))
+ generic_plugin = plugin;
+ else
+ priv->plugins = g_slist_append (priv->plugins, plugin);
+ }
}
+ /* Make sure the generic plugin is last */
+ if (generic_plugin)
+ priv->plugins = g_slist_append (priv->plugins, generic_plugin);
+
g_dir_close (dir);
}
@@ -138,7 +151,7 @@ mm_manager_new (DBusGConnection *bus)
if (manager) {
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
- priv->connection = bus;
+ priv->connection = dbus_g_connection_ref (bus);
dbus_g_connection_register_g_object (priv->connection,
MM_DBUS_PATH,
G_OBJECT (manager));
@@ -147,296 +160,441 @@ mm_manager_new (DBusGConnection *bus)
return manager;
}
-static char *
-get_driver_name (LibHalContext *ctx, const char *udi)
+static void
+remove_modem (MMManager *manager, MMModem *modem)
{
- char *parent_udi;
- char *driver = NULL;
+ MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
+ char *device;
- 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);
- }
+ device = mm_modem_get_device (modem);
+ g_assert (device);
+ g_debug ("Removed modem %s", device);
- return driver;
+ g_signal_emit (manager, signals[DEVICE_REMOVED], 0, modem);
+ g_hash_table_remove (priv->modems, device);
+ g_free (device);
}
-static MMModem *
-create_generic_modem (MMManager *manager, const char *udi)
+static void
+modem_valid (MMModem *modem, GParamSpec *pspec, gpointer user_data)
{
+ MMManager *manager = MM_MANAGER (user_data);
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
- MMModem *modem;
- char **capabilities;
- char **iter;
- char *serial_device;
- char *driver;
- gboolean type_gsm = FALSE;
- gboolean type_cdma = FALSE;
-
- capabilities = libhal_device_get_property_strlist (priv->hal_ctx, udi, "modem.command_sets", NULL);
- for (iter = capabilities; iter && *iter; iter++) {
- if (!strcmp (*iter, "GSM-07.07")) {
- type_gsm = TRUE;
- break;
- }
- if (!strcmp (*iter, "IS-707-A")) {
- type_cdma = TRUE;
- break;
- }
- }
- g_strfreev (capabilities);
-
- if (!type_gsm && !type_cdma)
- return NULL;
+ static guint32 id = 0;
+ char *path, *device;
- serial_device = libhal_device_get_property_string (priv->hal_ctx, udi, "serial.device", NULL);
- g_return_val_if_fail (serial_device != NULL, NULL);
+ if (mm_modem_get_valid (modem)) {
+ path = g_strdup_printf (MM_DBUS_PATH"/Modems/%d", id++);
+ dbus_g_connection_register_g_object (priv->connection, path, G_OBJECT (modem));
+ g_object_set_data_full (G_OBJECT (modem), DBUS_PATH_TAG, path, (GDestroyNotify) g_free);
- driver = get_driver_name (priv->hal_ctx, udi);
- g_return_val_if_fail (driver != NULL, NULL);
+ device = mm_modem_get_device (modem);
+ g_assert (device);
+ g_debug ("Exported modem %s as %s", device, path);
+ g_free (device);
- if (type_gsm)
- modem = mm_generic_gsm_new (serial_device, driver);
- else
- modem = mm_generic_cdma_new (serial_device, driver);
-
- g_free (serial_device);
- g_free (driver);
-
- if (modem)
- g_debug ("Created new generic modem (%s)", udi);
- else
- g_warning ("Failed to create generic modem (%s)", udi);
-
- return modem;
+ g_signal_emit (manager, signals[DEVICE_ADDED], 0, modem);
+ } else
+ remove_modem (manager, modem);
}
static void
-add_modem (MMManager *manager, const char *udi, MMModem *modem)
+add_modem (MMManager *manager, MMModem *modem)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
+ char *device;
+ gboolean valid = FALSE;
+
+ device = mm_modem_get_device (modem);
+ g_assert (device);
+ if (!g_hash_table_lookup (priv->modems, device)) {
+ g_hash_table_insert (priv->modems, g_strdup (device), modem);
+ g_debug ("Added modem %s", device);
+ g_signal_connect (modem, "notify::valid", G_CALLBACK (modem_valid), manager);
+ g_object_get (modem, MM_MODEM_VALID, &valid, NULL);
+ if (valid)
+ modem_valid (modem, NULL, manager);
+ }
+ g_free (device);
+}
- g_hash_table_insert (priv->modems, g_strdup (udi), modem);
- dbus_g_connection_register_g_object (priv->connection, udi, G_OBJECT (modem));
-
- g_signal_emit (manager, signals[DEVICE_ADDED], 0, modem);
+static void
+enumerate_devices_cb (gpointer key, gpointer val, gpointer user_data)
+{
+ MMModem *modem = MM_MODEM (val);
+ GPtrArray **devices = (GPtrArray **) user_data;
+ const char *path;
+ gboolean valid = FALSE;
+
+ g_object_get (G_OBJECT (modem), MM_MODEM_VALID, &valid, NULL);
+ if (valid) {
+ path = g_object_get_data (G_OBJECT (modem), DBUS_PATH_TAG);
+ g_return_if_fail (path != NULL);
+ g_ptr_array_add (*devices, g_strdup (path));
+ }
}
-static MMModem *
-modem_exists (MMManager *manager, const char *udi)
+static gboolean
+impl_manager_enumerate_devices (MMManager *manager,
+ GPtrArray **devices,
+ GError **err)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
- return (MMModem *) g_hash_table_lookup (priv->modems, udi);
+ *devices = g_ptr_array_sized_new (g_hash_table_size (priv->modems));
+ g_hash_table_foreach (priv->modems, enumerate_devices_cb, devices);
+
+ return TRUE;
}
-static void
-create_initial_modems_from_plugins (MMManager *manager)
+static MMModem *
+find_modem_for_port (MMManager *manager, const char *subsys, const char *name)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
- GSList *iter;
+ GHashTableIter iter;
+ gpointer key, value;
- for (iter = priv->plugins; iter; iter = iter->next) {
- MMPlugin *plugin = MM_PLUGIN (iter->data);
- char **udis;
- int i;
+ g_hash_table_iter_init (&iter, priv->modems);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ MMModem *modem = MM_MODEM (value);
- udis = mm_plugin_list_supported_udis (plugin, priv->hal_ctx);
- if (udis) {
- for (i = 0; udis[i]; i++) {
- char *udi = udis[i];
- MMModem *modem;
+ if (mm_modem_owns_port (modem, subsys, name))
+ return modem;
+ }
+ return NULL;
+}
- if (modem_exists (manager, udi)) {
- g_warning ("Modem for UDI %s already exists, ignoring", udi);
- continue;
- }
+typedef struct {
+ MMManager *manager;
+ char *subsys;
+ char *name;
+ GSList *plugins;
+ GSList *cur_plugin;
+ guint defer_id;
+ guint done_id;
- modem = mm_plugin_create_modem (plugin, priv->hal_ctx, udi);
- if (modem)
- add_modem (manager, udi, modem);
- }
+ guint32 best_level;
+ MMPlugin *best_plugin;
+} SupportsInfo;
- g_strfreev (udis);
- }
- }
+static SupportsInfo *
+supports_info_new (MMManager *self, const char *subsys, const char *name)
+{
+ MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (self);
+ SupportsInfo *info;
+
+ info = g_malloc0 (sizeof (SupportsInfo));
+ info->manager = self;
+ info->subsys = g_strdup (subsys);
+ info->name = g_strdup (name);
+ info->plugins = g_slist_copy (priv->plugins);
+ info->cur_plugin = info->plugins;
+ return info;
}
static void
-create_initial_modems_generic (MMManager *manager)
+supports_info_free (SupportsInfo *info)
{
- MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
- char **devices;
- int num_devices;
- int i;
- DBusError err;
-
- dbus_error_init (&err);
- devices = libhal_find_device_by_capability (priv->hal_ctx, "modem", &num_devices, &err);
- if (dbus_error_is_set (&err)) {
- g_warning ("Could not list HAL devices: %s", err.message);
- dbus_error_free (&err);
- }
+ /* Cancel any in-process operation on the first plugin */
+ if (info->cur_plugin)
+ mm_plugin_cancel_supports_port (MM_PLUGIN (info->cur_plugin->data), info->subsys, info->name);
- if (devices) {
- for (i = 0; i < num_devices; i++) {
- char *udi = devices[i];
- MMModem *modem;
+ if (info->defer_id)
+ g_source_remove (info->defer_id);
- if (modem_exists (manager, udi))
- /* Already exists, most likely handled by a plugin */
- continue;
+ if (info->done_id)
+ g_source_remove (info->done_id);
- modem = create_generic_modem (manager, udi);
- if (modem)
- add_modem (manager, g_strdup (udi), modem);
- }
- }
+ g_free (info->subsys);
+ g_free (info->name);
+ g_slist_free (info->plugins);
+ memset (info, 0, sizeof (SupportsInfo));
+ g_free (info);
+}
- g_strfreev (devices);
+static char *
+get_key (const char *subsys, const char *name)
+{
+ return g_strdup_printf ("%s%s", subsys, name);
}
-static void
-create_initial_modems (MMManager *manager)
+
+static void supports_callback (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ guint32 level,
+ gpointer user_data);
+
+static void try_supports_port (MMManager *manager,
+ MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ SupportsInfo *info);
+
+static gboolean
+supports_defer_timeout (gpointer user_data)
{
- create_initial_modems_from_plugins (manager);
- create_initial_modems_generic (manager);
+ SupportsInfo *info = user_data;
+
+ g_debug ("(%s): re-checking support...", info->name);
+ try_supports_port (info->manager,
+ MM_PLUGIN (info->cur_plugin->data),
+ info->subsys,
+ info->name,
+ info);
+ return FALSE;
}
static void
-enumerate_devices_cb (gpointer key, gpointer val, gpointer user_data)
+try_supports_port (MMManager *manager,
+ MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ SupportsInfo *info)
{
- GPtrArray **devices = (GPtrArray **) user_data;
-
- g_ptr_array_add (*devices, g_strdup ((char *) key));
+ MMPluginSupportsResult result;
+
+ result = mm_plugin_supports_port (plugin, subsys, name, supports_callback, info);
+
+ switch (result) {
+ case MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED:
+ /* If the plugin knows it doesn't support the modem, just call the
+ * callback and indicate 0 support.
+ */
+ supports_callback (plugin, subsys, name, 0, info);
+ break;
+ case MM_PLUGIN_SUPPORTS_PORT_DEFER:
+ g_debug ("(%s): (%s) deferring support check", mm_plugin_get_name (plugin), name);
+ if (info->defer_id)
+ g_source_remove (info->defer_id);
+
+ /* defer port detection for a bit as requested by the plugin */
+ info->defer_id = g_timeout_add (3000, supports_defer_timeout, info);
+ break;
+ case MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS:
+ default:
+ break;
+ }
}
static gboolean
-impl_manager_enumerate_devices (MMManager *manager,
- GPtrArray **devices,
- GError **err)
+do_grab_port (gpointer user_data)
{
- MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
+ SupportsInfo *info = user_data;
+ MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (info->manager);
+ MMModem *modem;
+ GError *error = NULL;
+ char *key;
+ GSList *iter;
- *devices = g_ptr_array_sized_new (g_hash_table_size (priv->modems));
- g_hash_table_foreach (priv->modems, enumerate_devices_cb, devices);
+ /* No more plugins to try */
+ if (info->best_plugin) {
+ /* Create the modem */
+ modem = mm_plugin_grab_port (info->best_plugin, info->subsys, info->name, &error);
+ if (modem) {
+ guint32 modem_type = MM_MODEM_TYPE_UNKNOWN;
+ const char *type_name = "UNKNOWN";
+
+ g_object_get (G_OBJECT (modem), MM_MODEM_TYPE, &modem_type, NULL);
+ if (modem_type == MM_MODEM_TYPE_GSM)
+ type_name = "GSM";
+ else if (modem_type == MM_MODEM_TYPE_CDMA)
+ type_name = "CDMA";
+
+ g_message ("(%s): %s modem %s claimed port %s",
+ mm_plugin_get_name (info->best_plugin),
+ type_name,
+ mm_modem_get_device (modem),
+ info->name);
+
+ add_modem (info->manager, modem);
+ } else {
+ g_warning ("%s: plugin '%s' claimed to support %s/%s but couldn't: (%d) %s",
+ __func__,
+ mm_plugin_get_name (info->best_plugin),
+ info->subsys,
+ info->name,
+ error ? error->code : -1,
+ (error && error->message) ? error->message : "(unknown)");
+ }
+ }
- return TRUE;
+ /* Tell each plugin to clean up any outstanding supports task */
+ for (iter = info->plugins; iter; iter = g_slist_next (iter))
+ mm_plugin_cancel_supports_port (MM_PLUGIN (iter->data), info->subsys, info->name);
+ g_slist_free (info->plugins);
+ info->cur_plugin = info->plugins = NULL;
+
+ key = get_key (info->subsys, info->name);
+ g_hash_table_remove (priv->supports, key);
+ g_free (key);
+
+ return FALSE;
}
static void
-device_added (LibHalContext *ctx, const char *udi)
+supports_callback (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ guint32 level,
+ gpointer user_data)
+{
+ SupportsInfo *info = user_data;
+ MMPlugin *next_plugin = NULL;
+
+ info->cur_plugin = info->cur_plugin->next;
+ if (info->cur_plugin)
+ next_plugin = MM_PLUGIN (info->cur_plugin->data);
+
+ /* Is this plugin's result better than any one we've tried before? */
+ if (level > info->best_level) {
+ info->best_level = level;
+ info->best_plugin = plugin;
+ }
+
+ /* Prevent the generic plugin from probing devices that are already supported
+ * by other plugins. For Huawei for example, secondary ports shouldn't
+ * be probed, but the generic plugin would happily do so if allowed to.
+ */
+ if ( next_plugin
+ && !strcmp (mm_plugin_get_name (next_plugin), MM_PLUGIN_GENERIC_NAME)
+ && info->best_plugin)
+ next_plugin = NULL;
+
+ if (next_plugin) {
+ /* Try the next plugin */
+ try_supports_port (info->manager, next_plugin, info->subsys, info->name, info);
+ } else {
+ /* All done; let the best modem grab the port */
+ info->done_id = g_idle_add (do_grab_port, info);
+ }
+}
+
+static void
+device_added (MMManager *manager, GUdevDevice *device)
{
- MMManager *manager = MM_MANAGER (libhal_ctx_get_user_data (ctx));
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
- GSList *iter;
- MMModem *modem = NULL;
+ const char *subsys, *name;
+ SupportsInfo *info;
+ char *key;
+ gboolean found;
+
+ g_return_if_fail (device != NULL);
- if (modem_exists (manager, udi))
- /* Shouldn't happen */
+ if (!g_slist_length (priv->plugins))
return;
- for (iter = priv->plugins; iter && modem == NULL; iter = iter->next) {
- MMPlugin *plugin = MM_PLUGIN (iter->data);
+ subsys = g_udev_device_get_subsystem (device);
+ name = g_udev_device_get_name (device);
- if (mm_plugin_supports_udi (plugin, ctx, udi)) {
- modem = mm_plugin_create_modem (plugin, ctx, udi);
- if (modem)
- break;
- }
+ if (find_modem_for_port (manager, subsys, name))
+ return;
+
+ key = get_key (subsys, name);
+ found = !!g_hash_table_lookup (priv->supports, key);
+ if (found) {
+ g_free (key);
+ return;
}
- if (!modem)
- /* None of the plugins supported the udi, try generic devices */
- modem = create_generic_modem (manager, udi);
+ info = supports_info_new (manager, subsys, name);
+ g_hash_table_insert (priv->supports, key, info);
- if (modem)
- add_modem (manager, udi, modem);
+ try_supports_port (manager, MM_PLUGIN (info->cur_plugin->data), subsys, name, info);
}
static void
-device_removed (LibHalContext *ctx, const char *udi)
+device_removed (MMManager *manager, GUdevDevice *device)
{
- MMManager *manager = MM_MANAGER (libhal_ctx_get_user_data (ctx));
+ MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
MMModem *modem;
+ const char *subsys, *name;
+ char *key;
+ SupportsInfo *info;
+
+ g_return_if_fail (device != NULL);
+
+ if (!g_slist_length (priv->plugins))
+ return;
- modem = modem_exists (manager, udi);
+ subsys = g_udev_device_get_subsystem (device);
+ name = g_udev_device_get_name (device);
+ modem = find_modem_for_port (manager, subsys, name);
if (modem) {
- g_debug ("Removed modem %s", udi);
- g_signal_emit (manager, signals[DEVICE_REMOVED], 0, modem);
- g_hash_table_remove (MM_MANAGER_GET_PRIVATE (manager)->modems, udi);
+ mm_modem_release_port (modem, subsys, name);
+ return;
}
-}
-static void
-device_new_capability (LibHalContext *ctx, const char *udi, const char *capability)
-{
- device_added (ctx, udi);
-}
+ /* Maybe a plugin is checking whether or not the port is supported */
+ key = get_key (subsys, name);
+ info = g_hash_table_lookup (priv->supports, key);
+ if (info) {
+ if (info->plugins)
+ mm_plugin_cancel_supports_port (MM_PLUGIN (info->plugins->data), subsys, name);
+ g_hash_table_remove (priv->supports, key);
+ }
-DBusGConnection *
-mm_manager_get_bus (MMManager *manager)
-{
- g_return_val_if_fail (MM_IS_MANAGER (manager), NULL);
-
- return MM_MANAGER_GET_PRIVATE (manager)->connection;
+ g_free (key);
}
-static gboolean
-remove_one (gpointer key,
- gpointer value,
- gpointer user_data)
+static void
+handle_uevent (GUdevClient *client,
+ const char *action,
+ GUdevDevice *device,
+ gpointer user_data)
{
- const char *udi = (char *) key;
- MMModem *modem = MM_MODEM (value);
- MMManager *manager = MM_MANAGER (user_data);
+ MMManager *self = MM_MANAGER (user_data);
+ const char *subsys;
- g_debug ("Removed modem %s", udi);
- g_signal_emit (manager, signals[DEVICE_REMOVED], 0, modem);
+ g_return_if_fail (action != NULL);
- return TRUE;
+ /* A bit paranoid */
+ subsys = g_udev_device_get_subsystem (device);
+ g_return_if_fail (subsys != NULL);
+
+ g_return_if_fail (!strcmp (subsys, "tty") || !strcmp (subsys, "net"));
+
+ if (!strcmp (action, "add"))
+ device_added (self, device);
+ else if (!strcmp (action, "remove"))
+ device_removed (self, device);
}
void
-mm_manager_set_hal_ctx (MMManager *manager,
- LibHalContext *hal_ctx)
+mm_manager_start (MMManager *manager)
{
MMManagerPrivate *priv;
+ GList *devices, *iter;
+ g_return_if_fail (manager != NULL);
g_return_if_fail (MM_IS_MANAGER (manager));
priv = MM_MANAGER_GET_PRIVATE (manager);
- priv->hal_ctx = hal_ctx;
- if (hal_ctx) {
- libhal_ctx_set_user_data (hal_ctx, manager);
- libhal_ctx_set_device_added (hal_ctx, device_added);
- libhal_ctx_set_device_removed (hal_ctx, device_removed);
- libhal_ctx_set_device_new_capability (hal_ctx, device_new_capability);
+ devices = g_udev_client_query_by_subsystem (priv->udev, "tty");
+ for (iter = devices; iter; iter = g_list_next (iter))
+ device_added (manager, G_UDEV_DEVICE (iter->data));
- create_initial_modems (manager);
- } else {
- g_hash_table_foreach_remove (priv->modems, remove_one, manager);
- }
-}
-
-LibHalContext *
-mm_manager_get_hal_ctx (MMManager *manager)
-{
- g_return_val_if_fail (MM_IS_MANAGER (manager), NULL);
-
- return MM_MANAGER_GET_PRIVATE (manager)->hal_ctx;
+ devices = g_udev_client_query_by_subsystem (priv->udev, "net");
+ for (iter = devices; iter; iter = g_list_next (iter))
+ device_added (manager, G_UDEV_DEVICE (iter->data));
}
static void
mm_manager_init (MMManager *manager)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
+ const char *subsys[3] = { "tty", "net", NULL };
priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
load_plugins (manager);
+
+ priv->supports = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) supports_info_free);
+
+ priv->udev = g_udev_client_new (subsys);
+ g_assert (priv->udev);
+ g_signal_connect (priv->udev, "uevent", G_CALLBACK (handle_uevent), manager);
}
static void
@@ -444,16 +602,14 @@ finalize (GObject *object)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (object);
+ g_hash_table_destroy (priv->supports);
g_hash_table_destroy (priv->modems);
g_slist_foreach (priv->plugins, (GFunc) g_object_unref, NULL);
g_slist_free (priv->plugins);
- if (priv->hal_ctx) {
- mm_manager_set_hal_ctx (MM_MANAGER (object), NULL);
- libhal_ctx_shutdown (priv->hal_ctx, NULL);
- libhal_ctx_free (priv->hal_ctx);
- }
+ if (priv->udev)
+ g_object_unref (priv->udev);
if (priv->connection)
dbus_g_connection_unref (priv->connection);
@@ -500,3 +656,4 @@ mm_manager_class_init (MMManagerClass *manager_class)
dbus_g_error_domain_register (MM_MODEM_CONNECT_ERROR, "org.freedesktop.ModemManager.Modem", MM_TYPE_MODEM_CONNECT_ERROR);
dbus_g_error_domain_register (MM_MOBILE_ERROR, "org.freedesktop.ModemManager.Modem.Gsm", MM_TYPE_MOBILE_ERROR);
}
+
diff --git a/src/mm-manager.h b/src/mm-manager.h
index 4426d0f1..0e7564ff 100644
--- a/src/mm-manager.h
+++ b/src/mm-manager.h
@@ -6,7 +6,6 @@
#include <glib/gtypes.h>
#include <glib-object.h>
#include <dbus/dbus-glib.h>
-#include <libhal.h>
#include "mm-modem.h"
#define MM_TYPE_MANAGER (mm_manager_get_type ())
@@ -34,10 +33,7 @@ typedef struct {
GType mm_manager_get_type (void);
MMManager *mm_manager_new (DBusGConnection *bus);
-DBusGConnection *mm_manager_get_bus (MMManager *manager);
-void mm_manager_set_hal_ctx (MMManager *manager,
- LibHalContext *hal_ctx);
-LibHalContext *mm_manager_get_hal_ctx (MMManager *manager);
+void mm_manager_start (MMManager *manager);
#endif /* MM_MANAGER_H */
diff --git a/src/mm-modem-base.c b/src/mm-modem-base.c
new file mode 100644
index 00000000..30de1123
--- /dev/null
+++ b/src/mm-modem-base.c
@@ -0,0 +1,156 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "mm-modem-base.h"
+#include "mm-serial-port.h"
+#include "mm-errors.h"
+#include "mm-options.h"
+
+G_DEFINE_TYPE (MMModemBase, mm_modem_base, G_TYPE_OBJECT)
+
+#define MM_MODEM_BASE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_BASE, MMModemBasePrivate))
+
+typedef struct {
+ GHashTable *ports;
+} MMModemBasePrivate;
+
+static char *
+get_hash_key (const char *subsys, const char *name)
+{
+ return g_strdup_printf ("%s%s", subsys, name);
+}
+
+MMPort *
+mm_modem_base_get_port (MMModemBase *self,
+ const char *subsys,
+ const char *name)
+{
+ MMPort *port;
+ char *key;
+
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (MM_IS_MODEM_BASE (self), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (subsys != NULL, NULL);
+
+ g_return_val_if_fail (!strcmp (subsys, "net") || !strcmp (subsys, "tty"), NULL);
+
+ key = get_hash_key (subsys, name);
+ port = g_hash_table_lookup (MM_MODEM_BASE_GET_PRIVATE (self)->ports, key);
+ g_free (key);
+ return port;
+}
+
+static void
+find_primary (gpointer key, gpointer data, gpointer user_data)
+{
+ MMPort **found = user_data;
+ MMPort *port = MM_PORT (data);
+
+ if (!*found && (mm_port_get_port_type (port) == MM_PORT_TYPE_PRIMARY))
+ *found = port;
+}
+
+MMPort *
+mm_modem_base_add_port (MMModemBase *self,
+ const char *subsys,
+ const char *name,
+ MMPortType ptype)
+{
+ MMModemBasePrivate *priv = MM_MODEM_BASE_GET_PRIVATE (self);
+ MMPort *port = NULL;
+ char *key;
+
+ g_return_val_if_fail (MM_IS_MODEM_BASE (self), NULL);
+ g_return_val_if_fail (subsys != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (ptype != MM_PORT_TYPE_UNKNOWN, NULL);
+
+ g_return_val_if_fail (!strcmp (subsys, "net") || !strcmp (subsys, "tty"), NULL);
+
+ key = get_hash_key (subsys, name);
+ port = g_hash_table_lookup (priv->ports, key);
+ g_free (key);
+ g_return_val_if_fail (port == NULL, NULL);
+
+ if (ptype == MM_PORT_TYPE_PRIMARY) {
+ g_hash_table_foreach (priv->ports, find_primary, &port);
+ g_return_val_if_fail (port == NULL, FALSE);
+ }
+
+ if (!strcmp (subsys, "tty"))
+ port = MM_PORT (mm_serial_port_new (name, ptype));
+ else if (!strcmp (subsys, "net")) {
+ port = MM_PORT (g_object_new (MM_TYPE_PORT,
+ MM_PORT_DEVICE, name,
+ MM_PORT_SUBSYS, MM_PORT_SUBSYS_NET,
+ MM_PORT_TYPE, ptype,
+ NULL));
+ }
+
+ if (!port)
+ return NULL;
+
+ key = get_hash_key (subsys, name);
+ g_hash_table_insert (priv->ports, key, port);
+ return port;
+}
+
+gboolean
+mm_modem_base_remove_port (MMModemBase *self, MMPort *port)
+{
+ g_return_val_if_fail (MM_IS_MODEM_BASE (self), FALSE);
+ g_return_val_if_fail (port != NULL, FALSE);
+
+ return g_hash_table_remove (MM_MODEM_BASE_GET_PRIVATE (self)->ports, port);
+}
+
+/*****************************************************************************/
+
+static void
+mm_modem_base_init (MMModemBase *self)
+{
+ MMModemBasePrivate *priv = MM_MODEM_BASE_GET_PRIVATE (self);
+
+ priv->ports = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+}
+
+static void
+finalize (GObject *object)
+{
+ MMModemBase *self = MM_MODEM_BASE (object);
+ MMModemBasePrivate *priv = MM_MODEM_BASE_GET_PRIVATE (self);
+
+ g_hash_table_destroy (priv->ports);
+
+ G_OBJECT_CLASS (mm_modem_base_parent_class)->finalize (object);
+}
+
+static void
+mm_modem_base_class_init (MMModemBaseClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMModemBasePrivate));
+
+ /* Virtual methods */
+ object_class->finalize = finalize;
+}
diff --git a/src/mm-modem-base.h b/src/mm-modem-base.h
new file mode 100644
index 00000000..9cb0df38
--- /dev/null
+++ b/src/mm-modem-base.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_MODEM_BASE_H
+#define MM_MODEM_BASE_H
+
+#include <glib.h>
+#include <glib/gtypes.h>
+#include <glib-object.h>
+
+#include "mm-port.h"
+
+#define MM_TYPE_MODEM_BASE (mm_modem_base_get_type ())
+#define MM_MODEM_BASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_BASE, MMModemBase))
+#define MM_MODEM_BASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_BASE, MMModemBaseClass))
+#define MM_IS_MODEM_BASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_BASE))
+#define MM_IS_MODEM_BASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_BASE))
+#define MM_MODEM_BASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_BASE, MMModemBaseClass))
+
+typedef struct _MMModemBase MMModemBase;
+typedef struct _MMModemBaseClass MMModemBaseClass;
+
+struct _MMModemBase {
+ GObject parent;
+};
+
+struct _MMModemBaseClass {
+ GObjectClass parent;
+};
+
+GType mm_modem_base_get_type (void);
+
+MMPort *mm_modem_base_get_port (MMModemBase *self,
+ const char *subsys,
+ const char *name);
+
+MMPort *mm_modem_base_add_port (MMModemBase *self,
+ const char *subsys,
+ const char *name,
+ MMPortType ptype);
+
+gboolean mm_modem_base_remove_port (MMModemBase *self,
+ MMPort *port);
+
+#endif /* MM_MODEM_BASE_H */
+
diff --git a/src/mm-modem-cdma.c b/src/mm-modem-cdma.c
index 5d921c99..01272590 100644
--- a/src/mm-modem-cdma.c
+++ b/src/mm-modem-cdma.c
@@ -7,6 +7,8 @@
#include "mm-callback-info.h"
static void impl_modem_cdma_get_signal_quality (MMModemCdma *modem, DBusGMethodInvocation *context);
+static void impl_modem_cdma_get_esn (MMModemCdma *modem, DBusGMethodInvocation *context);
+static void impl_modem_cdma_get_serving_system (MMModemCdma *modem, DBusGMethodInvocation *context);
#include "mm-modem-cdma-glue.h"
@@ -18,6 +20,33 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
+/*****************************************************************************/
+
+static void
+str_call_done (MMModem *modem, const char *result, 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, result);
+}
+
+static void
+str_call_not_supported (MMModemCdma *self,
+ MMModemStringFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_string_new (MM_MODEM (self), callback, user_data);
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED,
+ "Operation not supported");
+
+ mm_callback_info_schedule (info);
+}
+
static void
uint_op_not_supported (MMModem *self,
MMModemUIntFn callback,
@@ -42,6 +71,112 @@ uint_call_done (MMModem *modem, guint32 result, GError *error, gpointer user_dat
dbus_g_method_return (context, result);
}
+static void
+serving_system_call_done (MMModemCdma *self,
+ guint32 class,
+ char band,
+ guint32 sid,
+ GError *error,
+ gpointer user_data)
+{
+ DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
+
+ if (error)
+ dbus_g_method_return_error (context, error);
+ else {
+ GValueArray *array;
+ GValue value = { 0, };
+ char band_str[2] = { 0, 0 };
+
+ array = g_value_array_new (3);
+
+ /* Band Class */
+ g_value_init (&value, G_TYPE_UINT);
+ g_value_set_uint (&value, class);
+ g_value_array_append (array, &value);
+ g_value_unset (&value);
+
+ /* Band */
+ g_value_init (&value, G_TYPE_STRING);
+ band_str[0] = band;
+ g_value_set_string (&value, band_str);
+ g_value_array_append (array, &value);
+ g_value_unset (&value);
+
+ /* SID */
+ g_value_init (&value, G_TYPE_UINT);
+ g_value_set_uint (&value, sid);
+ g_value_array_append (array, &value);
+ g_value_unset (&value);
+
+ dbus_g_method_return (context, array);
+ }
+}
+
+static void
+serving_system_invoke (MMCallbackInfo *info)
+{
+ MMModemCdmaServingSystemFn callback = (MMModemCdmaServingSystemFn) info->callback;
+
+ callback (MM_MODEM_CDMA (info->modem), 0, 0, 0, info->error, info->user_data);
+}
+
+static void
+serving_system_call_not_supported (MMModemCdma *self,
+ MMModemCdmaServingSystemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new_full (MM_MODEM (self), serving_system_invoke, G_CALLBACK (callback), user_data);
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED,
+ "Operation not supported");
+
+ mm_callback_info_schedule (info);
+}
+
+void
+mm_modem_cdma_get_serving_system (MMModemCdma *self,
+ MMModemCdmaServingSystemFn callback,
+ gpointer user_data)
+{
+ g_return_if_fail (MM_IS_MODEM_CDMA (self));
+ g_return_if_fail (callback != NULL);
+
+ if (MM_MODEM_CDMA_GET_INTERFACE (self)->get_serving_system)
+ MM_MODEM_CDMA_GET_INTERFACE (self)->get_serving_system (self, callback, user_data);
+ else
+ serving_system_call_not_supported (self, callback, user_data);
+}
+
+static void
+impl_modem_cdma_get_serving_system (MMModemCdma *modem,
+ DBusGMethodInvocation *context)
+{
+ mm_modem_cdma_get_serving_system (modem, serving_system_call_done, context);
+}
+
+void
+mm_modem_cdma_get_esn (MMModemCdma *self,
+ MMModemStringFn callback,
+ gpointer user_data)
+{
+ g_return_if_fail (MM_IS_MODEM_CDMA (self));
+ g_return_if_fail (callback != NULL);
+
+ if (MM_MODEM_CDMA_GET_INTERFACE (self)->get_esn)
+ MM_MODEM_CDMA_GET_INTERFACE (self)->get_esn (self, callback, user_data);
+ else
+ str_call_not_supported (self, callback, user_data);
+}
+
+static void
+impl_modem_cdma_get_esn (MMModemCdma *modem,
+ DBusGMethodInvocation *context)
+{
+ mm_modem_cdma_get_esn (modem, str_call_done, context);
+}
+
void
mm_modem_cdma_get_signal_quality (MMModemCdma *self,
MMModemUIntFn callback,
@@ -71,7 +206,6 @@ mm_modem_cdma_signal_quality (MMModemCdma *self,
g_signal_emit (self, signals[SIGNAL_QUALITY], 0, quality);
}
-
/*****************************************************************************/
static void
diff --git a/src/mm-modem-cdma.h b/src/mm-modem-cdma.h
index 7910b63c..6a27a190 100644
--- a/src/mm-modem-cdma.h
+++ b/src/mm-modem-cdma.h
@@ -12,6 +12,13 @@
typedef struct _MMModemCdma MMModemCdma;
+typedef void (*MMModemCdmaServingSystemFn) (MMModemCdma *modem,
+ guint32 class,
+ char band,
+ guint32 sid,
+ GError *error,
+ gpointer user_data);
+
struct _MMModemCdma {
GTypeInterface g_iface;
@@ -20,6 +27,14 @@ struct _MMModemCdma {
MMModemUIntFn callback,
gpointer user_data);
+ void (*get_esn) (MMModemCdma *self,
+ MMModemStringFn callback,
+ gpointer user_data);
+
+ void (*get_serving_system) (MMModemCdma *self,
+ MMModemCdmaServingSystemFn callback,
+ gpointer user_data);
+
/* Signals */
void (*signal_quality) (MMModemCdma *self,
guint32 quality);
@@ -31,6 +46,14 @@ void mm_modem_cdma_get_signal_quality (MMModemCdma *self,
MMModemUIntFn callback,
gpointer user_data);
+void mm_modem_cdma_get_esn (MMModemCdma *self,
+ MMModemStringFn callback,
+ gpointer user_data);
+
+void mm_modem_cdma_get_serving_system (MMModemCdma *self,
+ MMModemCdmaServingSystemFn callback,
+ gpointer user_data);
+
/* Protected */
void mm_modem_cdma_signal_quality (MMModemCdma *self,
diff --git a/src/mm-modem-gsm-card.c b/src/mm-modem-gsm-card.c
index 85385b25..1ad48cd5 100644
--- a/src/mm-modem-gsm-card.c
+++ b/src/mm-modem-gsm-card.c
@@ -12,9 +12,6 @@ static void impl_gsm_modem_get_imei (MMModemGsmCard *modem,
static void impl_gsm_modem_get_imsi (MMModemGsmCard *modem,
DBusGMethodInvocation *context);
-static void impl_gsm_modem_get_info (MMModemGsmCard *modem,
- DBusGMethodInvocation *context);
-
static void impl_gsm_modem_send_pin (MMModemGsmCard *modem,
const char *pin,
DBusGMethodInvocation *context);
@@ -64,68 +61,6 @@ str_call_not_supported (MMModemGsmCard *self,
}
static void
-info_call_done (MMModemGsmCard *self,
- const char *manufacturer,
- const char *model,
- const char *version,
- GError *error,
- gpointer user_data)
-{
- DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
-
- if (error)
- dbus_g_method_return_error (context, error);
- else {
- GValueArray *array;
- GValue value = { 0, };
-
- array = g_value_array_new (3);
-
- /* Manufacturer */
- g_value_init (&value, G_TYPE_STRING);
- g_value_set_string (&value, manufacturer);
- g_value_array_append (array, &value);
- g_value_unset (&value);
-
- /* Model */
- g_value_init (&value, G_TYPE_STRING);
- g_value_set_string (&value, model);
- g_value_array_append (array, &value);
- g_value_unset (&value);
-
- /* Version */
- g_value_init (&value, G_TYPE_STRING);
- g_value_set_string (&value, version);
- g_value_array_append (array, &value);
- g_value_unset (&value);
-
- dbus_g_method_return (context, array);
- }
-}
-
-static void
-info_invoke (MMCallbackInfo *info)
-{
- MMModemGsmCardInfoFn callback = (MMModemGsmCardInfoFn) info->callback;
-
- callback (MM_MODEM_GSM_CARD (info->modem), NULL, NULL, NULL, info->error, info->user_data);
-}
-
-static void
-info_call_not_supported (MMModemGsmCard *self,
- MMModemGsmCardInfoFn callback,
- gpointer user_data)
-{
- MMCallbackInfo *info;
-
- info = mm_callback_info_new_full (MM_MODEM (self), info_invoke, G_CALLBACK (callback), user_data);
- info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED,
- "Operation not supported");
-
- mm_callback_info_schedule (info);
-}
-
-static void
async_call_done (MMModem *modem, GError *error, gpointer user_data)
{
DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
@@ -180,20 +115,6 @@ mm_modem_gsm_card_get_imsi (MMModemGsmCard *self,
}
void
-mm_modem_gsm_card_get_info (MMModemGsmCard *self,
- MMModemGsmCardInfoFn callback,
- gpointer user_data)
-{
- g_return_if_fail (MM_IS_MODEM_GSM_CARD (self));
- g_return_if_fail (callback != NULL);
-
- if (MM_MODEM_GSM_CARD_GET_INTERFACE (self)->get_info)
- MM_MODEM_GSM_CARD_GET_INTERFACE (self)->get_info (self, callback, user_data);
- else
- info_call_not_supported (self, callback, user_data);
-}
-
-void
mm_modem_gsm_card_send_puk (MMModemGsmCard *self,
const char *puk,
const char *pin,
@@ -279,13 +200,6 @@ impl_gsm_modem_get_imsi (MMModemGsmCard *modem,
}
static void
-impl_gsm_modem_get_info (MMModemGsmCard *modem,
- DBusGMethodInvocation *context)
-{
- mm_modem_gsm_card_get_info (modem, info_call_done, context);
-}
-
-static void
impl_gsm_modem_send_puk (MMModemGsmCard *modem,
const char *puk,
const char *pin,
diff --git a/src/mm-modem-gsm-card.h b/src/mm-modem-gsm-card.h
index 50323810..5c6f55f4 100644
--- a/src/mm-modem-gsm-card.h
+++ b/src/mm-modem-gsm-card.h
@@ -12,13 +12,6 @@
typedef struct _MMModemGsmCard MMModemGsmCard;
-typedef void (*MMModemGsmCardInfoFn) (MMModemGsmCard *self,
- const char *manufacturer,
- const char *model,
- const char *version,
- GError *error,
- gpointer user_data);
-
struct _MMModemGsmCard {
GTypeInterface g_iface;
@@ -31,10 +24,6 @@ struct _MMModemGsmCard {
MMModemStringFn callback,
gpointer user_data);
- void (*get_info) (MMModemGsmCard *self,
- MMModemGsmCardInfoFn callback,
- gpointer user_data);
-
void (*send_puk) (MMModemGsmCard *self,
const char *puk,
const char *pin,
@@ -69,10 +58,6 @@ void mm_modem_gsm_card_get_imsi (MMModemGsmCard *self,
MMModemStringFn callback,
gpointer user_data);
-void mm_modem_gsm_card_get_info (MMModemGsmCard *self,
- MMModemGsmCardInfoFn callback,
- gpointer user_data);
-
void mm_modem_gsm_card_send_puk (MMModemGsmCard *self,
const char *puk,
const char *pin,
diff --git a/src/mm-modem.c b/src/mm-modem.c
index 7bf913ec..3a566d08 100644
--- a/src/mm-modem.c
+++ b/src/mm-modem.c
@@ -10,6 +10,7 @@ static void impl_modem_enable (MMModem *modem, gboolean enable, DBusGMethodInvoc
static void impl_modem_connect (MMModem *modem, const char *number, DBusGMethodInvocation *context);
static void impl_modem_disconnect (MMModem *modem, DBusGMethodInvocation *context);
static void impl_modem_get_ip4_config (MMModem *modem, DBusGMethodInvocation *context);
+static void impl_modem_get_info (MMModem *modem, DBusGMethodInvocation *context);
#include "mm-modem-glue.h"
@@ -196,6 +197,158 @@ impl_modem_disconnect (MMModem *modem,
mm_modem_disconnect (modem, async_call_done, context);
}
+static void
+info_call_done (MMModem *self,
+ const char *manufacturer,
+ const char *model,
+ const char *version,
+ GError *error,
+ gpointer user_data)
+{
+ DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
+
+ if (error)
+ dbus_g_method_return_error (context, error);
+ else {
+ GValueArray *array;
+ GValue value = { 0, };
+
+ array = g_value_array_new (3);
+
+ /* Manufacturer */
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, manufacturer);
+ g_value_array_append (array, &value);
+ g_value_unset (&value);
+
+ /* Model */
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, model);
+ g_value_array_append (array, &value);
+ g_value_unset (&value);
+
+ /* Version */
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, version);
+ g_value_array_append (array, &value);
+ g_value_unset (&value);
+
+ dbus_g_method_return (context, array);
+ }
+}
+
+static void
+info_invoke (MMCallbackInfo *info)
+{
+ MMModemInfoFn callback = (MMModemInfoFn) info->callback;
+
+ callback (info->modem, NULL, NULL, NULL, info->error, info->user_data);
+}
+
+static void
+info_call_not_supported (MMModem *self,
+ MMModemInfoFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new_full (MM_MODEM (self), info_invoke, G_CALLBACK (callback), user_data);
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED,
+ "Operation not supported");
+
+ mm_callback_info_schedule (info);
+}
+
+void
+mm_modem_get_info (MMModem *self,
+ MMModemInfoFn callback,
+ gpointer user_data)
+{
+ g_return_if_fail (MM_IS_MODEM (self));
+ g_return_if_fail (callback != NULL);
+
+ if (MM_MODEM_GET_INTERFACE (self)->get_info)
+ MM_MODEM_GET_INTERFACE (self)->get_info (self, callback, user_data);
+ else
+ info_call_not_supported (self, callback, user_data);
+}
+
+static void
+impl_modem_get_info (MMModem *modem,
+ DBusGMethodInvocation *context)
+{
+ mm_modem_get_info (modem, info_call_done, context);
+}
+
+/*****************************************************************************/
+
+gboolean
+mm_modem_owns_port (MMModem *self,
+ const char *subsys,
+ const char *name)
+{
+ g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (MM_IS_MODEM (self), FALSE);
+ g_return_val_if_fail (subsys, FALSE);
+ g_return_val_if_fail (name, FALSE);
+
+ g_assert (MM_MODEM_GET_INTERFACE (self)->owns_port);
+ return MM_MODEM_GET_INTERFACE (self)->owns_port (self, subsys, name);
+}
+
+gboolean
+mm_modem_grab_port (MMModem *self,
+ const char *subsys,
+ const char *name,
+ gpointer user_data,
+ GError **error)
+{
+ g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (MM_IS_MODEM (self), FALSE);
+ g_return_val_if_fail (subsys, FALSE);
+ g_return_val_if_fail (name, FALSE);
+
+ g_assert (MM_MODEM_GET_INTERFACE (self)->grab_port);
+ return MM_MODEM_GET_INTERFACE (self)->grab_port (self, subsys, name, user_data, error);
+}
+
+void
+mm_modem_release_port (MMModem *self,
+ const char *subsys,
+ const char *name)
+{
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (MM_IS_MODEM (self));
+ g_return_if_fail (subsys);
+ g_return_if_fail (name);
+
+ g_assert (MM_MODEM_GET_INTERFACE (self)->release_port);
+ MM_MODEM_GET_INTERFACE (self)->release_port (self, subsys, name);
+}
+
+gboolean
+mm_modem_get_valid (MMModem *self)
+{
+ gboolean valid = FALSE;
+
+ g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (MM_IS_MODEM (self), FALSE);
+
+ g_object_get (G_OBJECT (self), MM_MODEM_VALID, &valid, NULL);
+ return valid;
+}
+
+char *
+mm_modem_get_device (MMModem *self)
+{
+ char *device;
+
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (MM_IS_MODEM (self), NULL);
+
+ g_object_get (G_OBJECT (self), MM_MODEM_MASTER_DEVICE, &device, NULL);
+ return device;
+}
/*****************************************************************************/
@@ -210,9 +363,17 @@ mm_modem_init (gpointer g_iface)
/* Properties */
g_object_interface_install_property
(g_iface,
- g_param_spec_string (MM_MODEM_DEVICE,
- "Device",
+ g_param_spec_string (MM_MODEM_DATA_DEVICE,
"Device",
+ "Data device",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_interface_install_property
+ (g_iface,
+ g_param_spec_string (MM_MODEM_MASTER_DEVICE,
+ "MasterDevice",
+ "Master modem parent device of all the modem's ports",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
@@ -226,6 +387,14 @@ mm_modem_init (gpointer g_iface)
g_object_interface_install_property
(g_iface,
+ g_param_spec_string (MM_MODEM_PLUGIN,
+ "Plugin",
+ "Plugin name",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_interface_install_property
+ (g_iface,
g_param_spec_uint (MM_MODEM_TYPE,
"Type",
"Type",
@@ -242,6 +411,14 @@ mm_modem_init (gpointer g_iface)
MM_MODEM_IP_METHOD_PPP,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_interface_install_property
+ (g_iface,
+ g_param_spec_boolean (MM_MODEM_VALID,
+ "Valid",
+ "Modem is valid",
+ FALSE,
+ G_PARAM_READABLE));
+
initialized = TRUE;
}
diff --git a/src/mm-modem.h b/src/mm-modem.h
index 914b86a3..9222b703 100644
--- a/src/mm-modem.h
+++ b/src/mm-modem.h
@@ -10,13 +10,17 @@
#define MM_IS_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM))
#define MM_MODEM_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_MODEM, MMModem))
-#define MM_MODEM_DEVICE "device"
-#define MM_MODEM_DRIVER "driver"
-#define MM_MODEM_TYPE "type"
-#define MM_MODEM_IP_METHOD "ip-method"
-
-#define MM_MODEM_TYPE_GSM 1
-#define MM_MODEM_TYPE_CDMA 2
+#define MM_MODEM_DATA_DEVICE "device"
+#define MM_MODEM_MASTER_DEVICE "master-device"
+#define MM_MODEM_DRIVER "driver"
+#define MM_MODEM_TYPE "type"
+#define MM_MODEM_IP_METHOD "ip-method"
+#define MM_MODEM_VALID "valid" /* not exported */
+#define MM_MODEM_PLUGIN "plugin" /* not exported */
+
+#define MM_MODEM_TYPE_UNKNOWN 0
+#define MM_MODEM_TYPE_GSM 1
+#define MM_MODEM_TYPE_CDMA 2
#define MM_MODEM_IP_METHOD_PPP 0
#define MM_MODEM_IP_METHOD_STATIC 1
@@ -25,10 +29,13 @@
typedef enum {
MM_MODEM_PROP_FIRST = 0x1000,
- MM_MODEM_PROP_DEVICE = MM_MODEM_PROP_FIRST,
+ MM_MODEM_PROP_DATA_DEVICE = MM_MODEM_PROP_FIRST,
+ MM_MODEM_PROP_MASTER_DEVICE,
MM_MODEM_PROP_DRIVER,
MM_MODEM_PROP_TYPE,
MM_MODEM_PROP_IP_METHOD,
+ MM_MODEM_PROP_VALID, /* Not exported */
+ MM_MODEM_PROP_PLUGIN, /* Not exported */
} MMModemProp;
typedef struct _MMModem MMModem;
@@ -53,10 +60,31 @@ typedef void (*MMModemIp4Fn) (MMModem *modem,
GError *error,
gpointer user_data);
+typedef void (*MMModemInfoFn) (MMModem *modem,
+ const char *manufacturer,
+ const char *model,
+ const char *version,
+ GError *error,
+ gpointer user_data);
+
struct _MMModem {
GTypeInterface g_iface;
/* Methods */
+ gboolean (*owns_port) (MMModem *self,
+ const char *subsys,
+ const char *name);
+
+ gboolean (*grab_port) (MMModem *self,
+ const char *subsys,
+ const char *name,
+ gpointer user_data,
+ GError **error);
+
+ void (*release_port) (MMModem *self,
+ const char *subsys,
+ const char *name);
+
void (*enable) (MMModem *self,
gboolean enable,
MMModemFn callback,
@@ -74,10 +102,28 @@ struct _MMModem {
void (*disconnect) (MMModem *self,
MMModemFn callback,
gpointer user_data);
+
+ void (*get_info) (MMModem *self,
+ MMModemInfoFn callback,
+ gpointer user_data);
};
GType mm_modem_get_type (void);
+gboolean mm_modem_owns_port (MMModem *self,
+ const char *subsys,
+ const char *name);
+
+gboolean mm_modem_grab_port (MMModem *self,
+ const char *subsys,
+ const char *name,
+ gpointer user_data,
+ GError **error);
+
+void mm_modem_release_port (MMModem *self,
+ const char *subsys,
+ const char *name);
+
void mm_modem_enable (MMModem *self,
gboolean enable,
MMModemFn callback,
@@ -96,4 +142,13 @@ void mm_modem_disconnect (MMModem *self,
MMModemFn callback,
gpointer user_data);
+void mm_modem_get_info (MMModem *self,
+ MMModemInfoFn callback,
+ gpointer user_data);
+
+gboolean mm_modem_get_valid (MMModem *self);
+
+char *mm_modem_get_device (MMModem *self);
+
#endif /* MM_MODEM_H */
+
diff --git a/src/mm-plugin-base.c b/src/mm-plugin-base.c
new file mode 100644
index 00000000..198108cf
--- /dev/null
+++ b/src/mm-plugin-base.c
@@ -0,0 +1,950 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+
+#include "mm-plugin-base.h"
+#include "mm-serial-port.h"
+#include "mm-serial-parsers.h"
+#include "mm-errors.h"
+#include "mm-marshal.h"
+
+static void plugin_init (MMPlugin *plugin_class);
+
+G_DEFINE_TYPE_EXTENDED (MMPluginBase, mm_plugin_base, G_TYPE_OBJECT,
+ 0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
+
+#define MM_PLUGIN_BASE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_PLUGIN_BASE, MMPluginBasePrivate))
+
+/* A hash table shared between all instances of the plugin base that
+ * caches the probed capabilities so that only one plugin has to actually
+ * probe a port.
+ */
+static GHashTable *cached_caps = NULL;
+
+
+typedef struct {
+ char *name;
+ GUdevClient *client;
+
+ GHashTable *modems;
+ GHashTable *tasks;
+} MMPluginBasePrivate;
+
+enum {
+ PROP_0,
+ PROP_NAME,
+ LAST_PROP
+};
+
+enum {
+ PROBE_RESULT,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+
+typedef enum {
+ PROBE_STATE_GCAP_TRY1 = 0,
+ PROBE_STATE_GCAP_TRY2,
+ PROBE_STATE_GCAP_TRY3,
+ PROBE_STATE_ATI,
+ PROBE_STATE_CGMM,
+ PROBE_STATE_LAST
+} ProbeState;
+
+/*****************************************************************************/
+
+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 {
+ MMPluginBase *plugin;
+ GUdevDevice *port;
+ GUdevDevice *physdev;
+ char *driver;
+
+ MMSerialPort *probe_port;
+ guint32 probed_caps;
+ ProbeState probe_state;
+ guint probe_id;
+ char *probe_resp;
+ GError *probe_error;
+
+ MMSupportsPortResultFunc callback;
+ gpointer callback_data;
+} MMPluginBaseSupportsTaskPrivate;
+
+static MMPluginBaseSupportsTask *
+supports_task_new (MMPluginBase *self,
+ GUdevDevice *port,
+ GUdevDevice *physdev,
+ const char *driver,
+ MMSupportsPortResultFunc callback,
+ gpointer callback_data)
+{
+ MMPluginBaseSupportsTask *task;
+ MMPluginBaseSupportsTaskPrivate *priv;
+
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (MM_IS_PLUGIN_BASE (self), NULL);
+ g_return_val_if_fail (port != NULL, NULL);
+ g_return_val_if_fail (physdev != NULL, NULL);
+ g_return_val_if_fail (driver != NULL, NULL);
+ g_return_val_if_fail (callback != NULL, NULL);
+
+ 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 = g_object_ref (physdev);
+ priv->driver = g_strdup (driver);
+ priv->callback = callback;
+ priv->callback_data = callback_data;
+
+ 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;
+}
+
+GUdevDevice *
+mm_plugin_base_supports_task_get_physdev (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;
+}
+
+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;
+}
+
+void
+mm_plugin_base_supports_task_complete (MMPluginBaseSupportsTask *task,
+ guint32 level)
+{
+ MMPluginBaseSupportsTaskPrivate *priv;
+ const char *subsys, *name;
+
+ g_return_if_fail (task != NULL);
+ g_return_if_fail (MM_IS_PLUGIN_BASE_SUPPORTS_TASK (task));
+
+ priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
+ g_return_if_fail (priv->callback != NULL);
+
+ subsys = g_udev_device_get_subsystem (priv->port);
+ name = g_udev_device_get_name (priv->port);
+
+ priv->callback (MM_PLUGIN (priv->plugin), subsys, name, level, priv->callback_data);
+
+ /* Clear out the callback, it shouldn't be called more than once */
+ priv->callback = NULL;
+ priv->callback_data = NULL;
+}
+
+static void
+mm_plugin_base_supports_task_init (MMPluginBaseSupportsTask *self)
+{
+}
+
+static void
+dispose (GObject *object)
+{
+ MMPluginBaseSupportsTaskPrivate *priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (object);
+
+ g_object_unref (priv->port);
+ g_object_unref (priv->physdev);
+ g_free (priv->driver);
+ g_free (priv->probe_resp);
+ g_clear_error (&(priv->probe_error));
+
+ if (priv->probe_id)
+ g_source_remove (priv->probe_id);
+ if (priv->probe_port)
+ g_object_unref (priv->probe_port);
+
+ 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 = 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},
+ {NULL}
+};
+
+static guint32
+parse_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_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 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 port */
+ g_object_unref (task_priv->probe_port);
+ task_priv->probe_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 *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
+
+ g_hash_table_insert (cached_caps,
+ g_strdup (mm_port_get_device (MM_PORT (task_priv->probe_port))),
+ GUINT_TO_POINTER (task_priv->probed_caps));
+
+ task_priv->probe_id = g_idle_add (emit_probe_result, task);
+}
+
+static void
+parse_response (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data);
+
+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);
+ MMSerialPort *port = task_priv->probe_port;
+ gboolean ignore_error = FALSE;
+
+ task_priv->probe_state++;
+
+ /* Some modems (Huawei E160g) won't respond to +GCAP with no SIM, but
+ * will respond to ATI.
+ */
+ if (response && strstr (response, "+CME ERROR:"))
+ ignore_error = TRUE;
+
+ if (error && !ignore_error) {
+ if (error->code == MM_SERIAL_RESPONSE_TIMEOUT) {
+ /* Try GCAP again */
+ if (task_priv->probe_state <= PROBE_STATE_GCAP_TRY3) {
+ mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, task);
+ return;
+ }
+
+ /* Otherwise, if all the GCAP tries timed out, ignore the port
+ * as it's probably not an AT-capable port.
+ */
+ probe_complete (task);
+ } else if (task_priv->probe_state <= PROBE_STATE_GCAP_TRY3) {
+ mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, task);
+ } else if (task_priv->probe_state == PROBE_STATE_ATI) {
+ /* Give ATI a try */
+ mm_serial_port_queue_command (port, "I", 3, parse_response, task);
+ } else if (task_priv->probe_state == PROBE_STATE_CGMM) {
+ /* If CGMM failed, probably not a modem port */
+ probe_complete (task);
+ }
+ return;
+ }
+
+ if (response) {
+ /* Parse the response */
+ task_priv->probed_caps = parse_gcap (response);
+
+ /* Some models (BUSlink SCWi275u) stick stupid stuff in the GMM response */
+ if ( (task_priv->probe_state == PROBE_STATE_LAST)
+ && !(task_priv->probed_caps & CAP_GSM_OR_CDMA))
+ task_priv->probed_caps = parse_cgmm (response);
+
+ if (task_priv->probed_caps & CAP_GSM_OR_CDMA) {
+ probe_complete (task);
+ return;
+ }
+ }
+
+ /* Try a different command */
+ switch (task_priv->probe_state) {
+ case PROBE_STATE_GCAP_TRY1:
+ case PROBE_STATE_GCAP_TRY2:
+ case PROBE_STATE_GCAP_TRY3:
+ mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, task);
+ break;
+ case PROBE_STATE_ATI:
+ /* After the last GCAP attempt, try ATI */
+ mm_serial_port_queue_command (port, "I", 3, parse_response, task);
+ break;
+ case PROBE_STATE_CGMM:
+ /* After the ATI attempt, try CGMM */
+ mm_serial_port_queue_command (port, "+CGMM", 3, parse_response, task);
+ break;
+ default:
+ /* Probably not GSM or CDMA */
+ probe_complete (task);
+ break;
+ }
+}
+
+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));
+ const char *cmd = NULL;
+
+ switch (task_priv->probe_state) {
+ case PROBE_STATE_GCAP_TRY1:
+ case PROBE_STATE_GCAP_TRY2:
+ case PROBE_STATE_GCAP_TRY3:
+ cmd = "+GCAP";
+ break;
+ case PROBE_STATE_ATI:
+ cmd = "I";
+ break;
+ case PROBE_STATE_CGMM:
+ default:
+ cmd = "+CGMM";
+ break;
+ }
+
+ MM_PLUGIN_BASE_GET_CLASS (self)->handle_probe_response (self,
+ task,
+ cmd,
+ task_priv->probe_resp,
+ task_priv->probe_error);
+ return FALSE;
+}
+
+static void
+parse_response (MMSerialPort *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
+flash_done (MMSerialPort *port, gpointer user_data)
+{
+ MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data);
+ MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
+
+ task_priv->probe_id = 0;
+ mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, user_data);
+}
+
+gboolean
+mm_plugin_base_probe_port (MMPluginBase *self,
+ MMPluginBaseSupportsTask *task,
+ GError **error)
+{
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
+ MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task);
+ MMSerialPort *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_serial_port_new (name, MM_PORT_TYPE_PRIMARY);
+ g_object_set (serial,
+ MM_SERIAL_PORT_SEND_DELAY, 100000,
+ MM_PORT_CARRIER_DETECT, FALSE,
+ NULL);
+
+ mm_serial_port_set_response_parser (serial,
+ mm_serial_parser_v1_parse,
+ mm_serial_parser_v1_new (),
+ mm_serial_parser_v1_destroy);
+
+ if (!mm_serial_port_open (serial, error)) {
+ g_object_unref (serial);
+ return FALSE;
+ }
+
+ g_debug ("(%s): probe requested by plugin '%s'", name, priv->name);
+ task_priv->probe_port = serial;
+ task_priv->probe_id = mm_serial_port_flash (serial, 100, flash_done, task);
+ return TRUE;
+}
+
+gboolean
+mm_plugin_base_get_cached_port_capabilities (MMPluginBase *self,
+ GUdevDevice *port,
+ guint32 *capabilities)
+{
+ gpointer tmp = NULL;
+ gboolean found;
+
+ found = g_hash_table_lookup_extended (cached_caps, g_udev_device_get_name (port), NULL, tmp);
+ *capabilities = GPOINTER_TO_UINT (tmp);
+ return found;
+}
+
+/*****************************************************************************/
+
+static void
+modem_destroyed (gpointer data, GObject *modem)
+{
+ MMPluginBase *self = MM_PLUGIN_BASE (data);
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
+ GHashTableIter iter;
+ gpointer key, value;
+
+ /* Remove it from the modems info */
+ g_hash_table_iter_init (&iter, priv->modems);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ if (value == modem) {
+ g_hash_table_iter_remove (&iter);
+ break;
+ }
+ }
+
+ /* 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 (cached_caps);
+}
+
+MMModem *
+mm_plugin_base_find_modem (MMPluginBase *self,
+ const char *master_device)
+{
+ MMPluginBasePrivate *priv;
+
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (MM_IS_PLUGIN_BASE (self), NULL);
+ g_return_val_if_fail (master_device != NULL, NULL);
+ g_return_val_if_fail (strlen (master_device) > 0, NULL);
+
+ priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
+ return g_hash_table_lookup (priv->modems, master_device);
+}
+
+/* From hostap, Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> */
+
+static int hex2num (char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+static int hex2byte (const char *hex)
+{
+ int a, b;
+ a = hex2num(*hex++);
+ if (a < 0)
+ return -1;
+ b = hex2num(*hex++);
+ if (b < 0)
+ return -1;
+ return (a << 4) | b;
+}
+
+/* End from hostap */
+
+gboolean
+mm_plugin_base_get_device_ids (MMPluginBase *self,
+ const char *subsys,
+ const char *name,
+ guint16 *vendor,
+ guint16 *product)
+{
+ MMPluginBasePrivate *priv;
+ GUdevDevice *device = NULL;
+ const char *vid, *pid;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (MM_IS_PLUGIN_BASE (self), FALSE);
+ g_return_val_if_fail (subsys != NULL, FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+ if (vendor)
+ g_return_val_if_fail (*vendor == 0, FALSE);
+ if (product)
+ g_return_val_if_fail (*product == 0, FALSE);
+
+ priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
+
+ device = g_udev_client_query_by_subsystem_and_name (priv->client, subsys, name);
+ if (!device)
+ goto out;
+
+ vid = g_udev_device_get_property (device, "ID_VENDOR_ID");
+ if (!vid || (strlen (vid) != 4))
+ goto out;
+
+ if (vendor) {
+ *vendor = (guint16) (hex2byte (vid + 2) & 0xFF);
+ *vendor |= (guint16) ((hex2byte (vid) & 0xFF) << 8);
+ }
+
+ pid = g_udev_device_get_property (device, "ID_MODEL_ID");
+ if (!pid || (strlen (pid) != 4)) {
+ *vendor = 0;
+ goto out;
+ }
+
+ if (product) {
+ *product = (guint16) (hex2byte (pid + 2) & 0xFF);
+ *product |= (guint16) ((hex2byte (pid) & 0xFF) << 8);
+ }
+
+ success = TRUE;
+
+out:
+ if (device)
+ g_object_unref (device);
+ return success;
+}
+
+static char *
+get_key (const char *subsys, const char *name)
+{
+ return g_strdup_printf ("%s%s", subsys, name);
+}
+
+static const char *
+get_name (MMPlugin *plugin)
+{
+ return MM_PLUGIN_BASE_GET_PRIVATE (plugin)->name;
+}
+
+static char *
+get_driver_name (GUdevDevice *device)
+{
+ GUdevDevice *parent = NULL;
+ const char *driver;
+ char *ret;
+
+ driver = g_udev_device_get_driver (device);
+ if (!driver) {
+ parent = g_udev_device_get_parent (device);
+ if (parent)
+ driver = g_udev_device_get_driver (parent);
+ }
+
+ if (driver)
+ ret = g_strdup (driver);
+ if (parent)
+ g_object_unref (parent);
+
+ return ret;
+}
+
+static GUdevDevice *
+real_find_physical_device (MMPluginBase *plugin, GUdevDevice *child)
+{
+ GUdevDevice *iter, *old = NULL;
+ GUdevDevice *physdev = NULL;
+ const char *subsys, *type;
+ guint32 i = 0;
+ gboolean is_usb = FALSE, is_pci = FALSE;
+
+ g_return_val_if_fail (child != NULL, NULL);
+
+ iter = g_object_ref (child);
+ while (iter && i++ < 5) {
+ subsys = g_udev_device_get_subsystem (iter);
+ if (subsys) {
+ if (is_usb || !strcmp (subsys, "usb")) {
+ is_usb = TRUE;
+ type = g_udev_device_get_devtype (iter);
+ if (type && !strcmp (type, "usb_device")) {
+ physdev = iter;
+ break;
+ }
+ } else if (is_pci || !strcmp (subsys, "pci")) {
+ is_pci = TRUE;
+ physdev = iter;
+ break;
+ }
+ }
+
+ old = iter;
+ iter = g_udev_device_get_parent (old);
+ g_object_unref (old);
+ }
+
+ return physdev;
+}
+
+static MMPluginSupportsResult
+supports_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ MMSupportsPortResultFunc callback,
+ gpointer callback_data)
+{
+ MMPluginBase *self = MM_PLUGIN_BASE (plugin);
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
+ GUdevDevice *port = NULL, *physdev = NULL;
+ char *driver = NULL, *key = NULL;
+ MMPluginBaseSupportsTask *task;
+ MMPluginSupportsResult result = MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ MMModem *existing;
+ const char *master_path;
+
+ 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, MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED);
+ }
+
+ port = g_udev_client_query_by_subsystem_and_name (priv->client, subsys, name);
+ if (!port)
+ goto out;
+
+ physdev = MM_PLUGIN_BASE_GET_CLASS (self)->find_physical_device (self, port);
+ if (!physdev)
+ goto out;
+
+ driver = get_driver_name (port);
+ if (!driver)
+ goto out;
+
+ task = supports_task_new (self, port, physdev, driver, callback, callback_data);
+ g_assert (task);
+ g_hash_table_insert (priv->tasks, g_strdup (key), g_object_ref (task));
+
+ /* Help the plugin out a bit by finding an existing modem for this port */
+ master_path = g_udev_device_get_sysfs_path (physdev);
+ existing = g_hash_table_lookup (priv->modems, master_path);
+
+ result = MM_PLUGIN_BASE_GET_CLASS (self)->supports_port (self, existing, task);
+ if (result != MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS) {
+ /* 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);
+
+out:
+ if (physdev)
+ g_object_unref (physdev);
+ if (port)
+ g_object_unref (port);
+ g_free (key);
+ g_free (driver);
+ return result;
+}
+
+static void
+cancel_supports_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name)
+{
+ MMPluginBase *self = MM_PLUGIN_BASE (plugin);
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
+ MMPluginBaseSupportsTask *task;
+ char *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);
+ g_hash_table_remove (priv->tasks, key);
+ }
+
+ g_free (key);
+}
+
+static MMModem *
+grab_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ GError **error)
+{
+ MMPluginBase *self = MM_PLUGIN_BASE (plugin);
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
+ MMPluginBaseSupportsTask *task;
+ char *key;
+ MMModem *existing = NULL, *modem = NULL;
+ const char *master_path;
+
+ 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);
+ }
+
+ /* Help the plugin out a bit by finding an existing modem for this port */
+ master_path = g_udev_device_get_sysfs_path (mm_plugin_base_supports_task_get_physdev (task));
+ existing = g_hash_table_lookup (priv->modems, master_path);
+
+ /* Let the modem grab the port */
+ modem = MM_PLUGIN_BASE_GET_CLASS (self)->grab_port (self, existing, task, error);
+ if (modem && !existing) {
+ g_hash_table_insert (priv->modems, g_strdup (master_path), modem);
+ g_object_weak_ref (G_OBJECT (modem), modem_destroyed, self);
+ }
+
+ g_hash_table_remove (priv->tasks, key);
+ g_free (key);
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+plugin_init (MMPlugin *plugin_class)
+{
+ /* interface implementation */
+ plugin_class->get_name = get_name;
+ plugin_class->supports_port = supports_port;
+ plugin_class->cancel_supports_port = cancel_supports_port;
+ plugin_class->grab_port = grab_port;
+}
+
+static void
+mm_plugin_base_init (MMPluginBase *self)
+{
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (self);
+ const char *subsys[] = { "tty", "net", NULL };
+
+ if (!cached_caps)
+ cached_caps = g_hash_table_new (g_str_hash, g_str_equal);
+
+ priv->client = g_udev_client_new (subsys);
+
+ priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ priv->tasks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify) g_object_unref);
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (object);
+
+ switch (prop_id) {
+ case PROP_NAME:
+ /* Construct only */
+ priv->name = 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)
+{
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (object);
+
+ switch (prop_id) {
+ case PROP_NAME:
+ g_value_set_string (value, priv->name);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+finalize (GObject *object)
+{
+ MMPluginBasePrivate *priv = MM_PLUGIN_BASE_GET_PRIVATE (object);
+
+ g_free (priv->name);
+
+ g_object_unref (priv->client);
+
+ g_hash_table_destroy (priv->modems);
+ g_hash_table_destroy (priv->tasks);
+
+ G_OBJECT_CLASS (mm_plugin_base_parent_class)->finalize (object);
+}
+
+static void
+mm_plugin_base_class_init (MMPluginBaseClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMPluginBasePrivate));
+
+ klass->find_physical_device = real_find_physical_device;
+ klass->handle_probe_response = real_handle_probe_response;
+
+ /* Virtual methods */
+ object_class->get_property = get_property;
+ object_class->set_property = set_property;
+ object_class->finalize = finalize;
+
+ g_object_class_install_property
+ (object_class, PROP_NAME,
+ g_param_spec_string (MM_PLUGIN_BASE_NAME,
+ "Name",
+ "Name",
+ NULL,
+ 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
new file mode 100644
index 00000000..91d3ddba
--- /dev/null
+++ b/src/mm-plugin-base.h
@@ -0,0 +1,145 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_PLUGIN_BASE_H
+#define MM_PLUGIN_BASE_H
+
+#include <glib.h>
+#include <glib/gtypes.h>
+#include <glib-object.h>
+
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+
+#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_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);
+
+MMPlugin *mm_plugin_base_supports_task_get_plugin (MMPluginBaseSupportsTask *task);
+
+GUdevDevice *mm_plugin_base_supports_task_get_port (MMPluginBaseSupportsTask *task);
+
+GUdevDevice *mm_plugin_base_supports_task_get_physdev (MMPluginBaseSupportsTask *task);
+
+const char *mm_plugin_base_supports_task_get_driver (MMPluginBaseSupportsTask *task);
+
+guint32 mm_plugin_base_supports_task_get_probed_capabilities (MMPluginBaseSupportsTask *task);
+
+void mm_plugin_base_supports_task_complete (MMPluginBaseSupportsTask *task,
+ guint32 level);
+
+
+#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))
+#define MM_PLUGIN_BASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_BASE, MMPluginBaseClass))
+#define MM_IS_PLUGIN_BASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_BASE))
+#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))
+
+#define MM_PLUGIN_BASE_NAME "name"
+
+typedef struct _MMPluginBase MMPluginBase;
+typedef struct _MMPluginBaseClass MMPluginBaseClass;
+
+struct _MMPluginBase {
+ GObject parent;
+};
+
+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,
+ GError **error);
+
+ /* Optional subclass functions */
+ void (*cancel_task) (MMPluginBase *plugin,
+ MMPluginBaseSupportsTask *task);
+
+ /* Find a the physical device of a port, ie the USB or PCI or whatever
+ * "master" device that owns the port. The GUdevDevice object returned
+ * will be unref-ed by the caller.
+ */
+ GUdevDevice * (*find_physical_device) (MMPluginBase *plugin,
+ GUdevDevice *port);
+
+ 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);
+
+MMModem *mm_plugin_base_find_modem (MMPluginBase *self,
+ const char *master_device);
+
+gboolean mm_plugin_base_get_device_ids (MMPluginBase *self,
+ const char *subsys,
+ const char *name,
+ guint16 *vendor,
+ guint16 *product);
+
+gboolean mm_plugin_base_probe_port (MMPluginBase *self,
+ MMPluginBaseSupportsTask *task,
+ GError **error);
+
+/* Returns TRUE if the port was previously probed, FALSE if not */
+gboolean mm_plugin_base_get_cached_port_capabilities (MMPluginBase *self,
+ GUdevDevice *port,
+ guint32 *capabilities);
+
+#endif /* MM_PLUGIN_BASE_H */
+
diff --git a/src/mm-plugin.c b/src/mm-plugin.c
index e1fd21c1..12df9dab 100644
--- a/src/mm-plugin.c
+++ b/src/mm-plugin.c
@@ -10,49 +10,46 @@ mm_plugin_get_name (MMPlugin *plugin)
return MM_PLUGIN_GET_INTERFACE (plugin)->get_name (plugin);
}
-char **
-mm_plugin_list_supported_udis (MMPlugin *plugin,
- LibHalContext *hal_ctx)
+MMPluginSupportsResult
+mm_plugin_supports_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ MMSupportsPortResultFunc callback,
+ gpointer user_data)
{
- g_return_val_if_fail (MM_IS_PLUGIN (plugin), NULL);
- g_return_val_if_fail (hal_ctx != NULL, NULL);
+ g_return_val_if_fail (MM_IS_PLUGIN (plugin), FALSE);
+ g_return_val_if_fail (subsys != NULL, FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+ g_return_val_if_fail (callback != NULL, FALSE);
- return MM_PLUGIN_GET_INTERFACE (plugin)->list_supported_udis (plugin, hal_ctx);
+ return MM_PLUGIN_GET_INTERFACE (plugin)->supports_port (plugin, subsys, name, callback, user_data);
}
-gboolean
-mm_plugin_supports_udi (MMPlugin *plugin,
- LibHalContext *hal_ctx,
- const char *udi)
+void
+mm_plugin_cancel_supports_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name)
{
- g_return_val_if_fail (MM_IS_PLUGIN (plugin), FALSE);
- g_return_val_if_fail (hal_ctx != NULL, FALSE);
- g_return_val_if_fail (udi != NULL, FALSE);
+ g_return_if_fail (MM_IS_PLUGIN (plugin));
+ g_return_if_fail (subsys != NULL);
+ g_return_if_fail (name != NULL);
- return MM_PLUGIN_GET_INTERFACE (plugin)->supports_udi (plugin, hal_ctx, udi);
+ MM_PLUGIN_GET_INTERFACE (plugin)->cancel_supports_port (plugin, subsys, name);
}
MMModem *
-mm_plugin_create_modem (MMPlugin *plugin,
- LibHalContext *hal_ctx,
- const char *udi)
+mm_plugin_grab_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ GError **error)
{
- MMModem *modem;
-
- g_return_val_if_fail (MM_IS_PLUGIN (plugin), NULL);
- g_return_val_if_fail (hal_ctx != NULL, NULL);
- g_return_val_if_fail (udi != NULL, NULL);
-
- modem = MM_PLUGIN_GET_INTERFACE (plugin)->create_modem (plugin, hal_ctx, udi);
- if (modem)
- g_debug ("Created new %s modem (%s)", mm_plugin_get_name (plugin), udi);
- else
- g_warning ("Failed to create %s modem (%s)", mm_plugin_get_name (plugin), udi);
+ g_return_val_if_fail (MM_IS_PLUGIN (plugin), FALSE);
+ g_return_val_if_fail (subsys != NULL, FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
- return modem;
+ return MM_PLUGIN_GET_INTERFACE (plugin)->grab_port (plugin, subsys, name, error);
}
-
/*****************************************************************************/
static void
diff --git a/src/mm-plugin.h b/src/mm-plugin.h
index 0f9a600b..3fa3a2cb 100644
--- a/src/mm-plugin.h
+++ b/src/mm-plugin.h
@@ -4,10 +4,11 @@
#define MM_PLUGIN_H
#include <glib-object.h>
-#include <libhal.h>
#include <mm-modem.h>
-#define MM_PLUGIN_MAJOR_VERSION 1
+#define MM_PLUGIN_GENERIC_NAME "Generic"
+
+#define MM_PLUGIN_MAJOR_VERSION 3
#define MM_PLUGIN_MINOR_VERSION 0
#define MM_TYPE_PLUGIN (mm_plugin_get_type ())
@@ -19,37 +20,87 @@ typedef struct _MMPlugin MMPlugin;
typedef MMPlugin *(*MMPluginCreateFunc) (void);
+/*
+ * 'level' is a value between 0 and 100 inclusive, where 0 means the plugin has
+ * no support for the port, and 100 means the plugin has full support for the
+ * port.
+ */
+typedef void (*MMSupportsPortResultFunc) (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ guint32 level,
+ gpointer user_data);
+
+typedef enum {
+ MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED = 0x0,
+ MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS,
+ MM_PLUGIN_SUPPORTS_PORT_DEFER
+} MMPluginSupportsResult;
+
struct _MMPlugin {
GTypeInterface g_iface;
/* Methods */
- const char *(*get_name) (MMPlugin *self);
-
- char **(*list_supported_udis) (MMPlugin *self,
- LibHalContext *hal_ctx);
-
- gboolean (*supports_udi) (MMPlugin *self,
- LibHalContext *hal_ctx,
- const char *udi);
-
- MMModem *(*create_modem) (MMPlugin *self,
- LibHalContext *hal_ctx,
- const char *udi);
+ const char *(*get_name) (MMPlugin *self);
+
+ /* Check whether a plugin supports a particular modem port, and what level
+ * of support the plugin has for the device. If the plugin can immediately
+ * determine whether a port is unsupported, it should return
+ * FALSE. Otherwise, if the plugin needs to perform additional operations
+ * (ie, probing) to determine the level of support or additional details
+ * about a port, it should queue that operation (but *not* block on the
+ * result) and return TRUE to indicate the operation is ongoing. When the
+ * operation is finished or the level of support is known, the plugin should
+ * call the provided callback and pass that callback the provided user_data.
+ */
+ MMPluginSupportsResult (*supports_port) (MMPlugin *self,
+ const char *subsys,
+ const char *name,
+ MMSupportsPortResultFunc callback,
+ gpointer user_data);
+
+ /* Called to cancel an ongoing supports_port() operation or to notify the
+ * plugin to clean up that operation. For example, if two plugins support
+ * a particular port, but the first plugin grabs the port, this method will
+ * be called on the second plugin to allow that plugin to clean up resources
+ * used while determining it's level of support for the port.
+ */
+ void (*cancel_supports_port) (MMPlugin *self,
+ const char *subsys,
+ const char *name);
+
+ /* Will only be called if the plugin returns a value greater than 0 for
+ * the supports_port() method for this port. The plugin should create and
+ * return a new modem for the port's device if there is no existing modem
+ * to handle the port's hardware device, or should add the port to an
+ * existing modem and return that modem object. If an error is encountered
+ * while claiming the port, the error information should be returned in the
+ * error argument, and the plugin should return NULL.
+ */
+ MMModem * (*grab_port) (MMPlugin *self,
+ const char *subsys,
+ const char *name,
+ GError **error);
};
GType mm_plugin_get_type (void);
-const char *mm_plugin_get_name (MMPlugin *plugin);
+const char *mm_plugin_get_name (MMPlugin *plugin);
-char **mm_plugin_list_supported_udis (MMPlugin *plugin,
- LibHalContext *hal_ctx);
+MMPluginSupportsResult mm_plugin_supports_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ MMSupportsPortResultFunc callback,
+ gpointer user_data);
-gboolean mm_plugin_supports_udi (MMPlugin *plugin,
- LibHalContext *hal_ctx,
- const char *udi);
+void mm_plugin_cancel_supports_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name);
-MMModem *mm_plugin_create_modem (MMPlugin *plugin,
- LibHalContext *hal_ctx,
- const char *udi);
+MMModem *mm_plugin_grab_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name,
+ GError **error);
#endif /* MM_PLUGIN_H */
+
diff --git a/src/mm-port.c b/src/mm-port.c
new file mode 100644
index 00000000..715db958
--- /dev/null
+++ b/src/mm-port.c
@@ -0,0 +1,238 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "mm-port.h"
+
+G_DEFINE_TYPE (MMPort, mm_port, G_TYPE_OBJECT)
+
+enum {
+ PROP_0,
+ PROP_DEVICE,
+ PROP_SUBSYS,
+ PROP_TYPE,
+ PROP_CARRIER_DETECT,
+
+ LAST_PROP
+};
+
+#define MM_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_PORT, MMPortPrivate))
+
+typedef struct {
+ char *device;
+ MMPortSubsys subsys;
+ MMPortType ptype;
+ gboolean carrier_detect;
+} MMPortPrivate;
+
+/*****************************************************************************/
+
+static GObject*
+constructor (GType type,
+ guint n_construct_params,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ MMPortPrivate *priv;
+
+ object = G_OBJECT_CLASS (mm_port_parent_class)->constructor (type,
+ n_construct_params,
+ construct_params);
+ if (!object)
+ return NULL;
+
+ priv = MM_PORT_GET_PRIVATE (object);
+
+ if (!priv->device) {
+ g_warning ("MMPort: no device provided");
+ g_object_unref (object);
+ return NULL;
+ }
+
+ if (priv->subsys == MM_PORT_SUBSYS_UNKNOWN) {
+ g_warning ("MMPort: invalid port subsystem");
+ g_object_unref (object);
+ return NULL;
+ }
+
+ if (priv->ptype == MM_PORT_TYPE_UNKNOWN) {
+ g_warning ("MMPort: invalid port type");
+ g_object_unref (object);
+ return NULL;
+ }
+
+ return object;
+}
+
+
+const char *
+mm_port_get_device (MMPort *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (MM_IS_PORT (self), NULL);
+
+ return MM_PORT_GET_PRIVATE (self)->device;
+}
+
+MMPortSubsys
+mm_port_get_subsys (MMPort *self)
+{
+ g_return_val_if_fail (self != NULL, MM_PORT_SUBSYS_UNKNOWN);
+ g_return_val_if_fail (MM_IS_PORT (self), MM_PORT_SUBSYS_UNKNOWN);
+
+ return MM_PORT_GET_PRIVATE (self)->subsys;
+}
+
+MMPortType
+mm_port_get_port_type (MMPort *self)
+{
+ g_return_val_if_fail (self != NULL, MM_PORT_TYPE_UNKNOWN);
+ g_return_val_if_fail (MM_IS_PORT (self), MM_PORT_TYPE_UNKNOWN);
+
+ return MM_PORT_GET_PRIVATE (self)->ptype;
+}
+
+gboolean
+mm_port_get_carrier_detect (MMPort *self)
+{
+ g_return_val_if_fail (self != NULL, MM_PORT_TYPE_UNKNOWN);
+ g_return_val_if_fail (MM_IS_PORT (self), MM_PORT_TYPE_UNKNOWN);
+
+ return MM_PORT_GET_PRIVATE (self)->carrier_detect;
+}
+
+/*****************************************************************************/
+
+static void
+mm_port_init (MMPort *self)
+{
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ MMPortPrivate *priv = MM_PORT_GET_PRIVATE (object);
+
+ switch (prop_id) {
+ case PROP_DEVICE:
+ /* Construct only */
+ priv->device = g_value_dup_string (value);
+ break;
+ case PROP_SUBSYS:
+ /* Construct only */
+ priv->subsys = g_value_get_uint (value);
+ break;
+ case PROP_TYPE:
+ /* Construct only */
+ priv->ptype = g_value_get_uint (value);
+ break;
+ case PROP_CARRIER_DETECT:
+ priv->carrier_detect = g_value_get_boolean (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)
+{
+ MMPortPrivate *priv = MM_PORT_GET_PRIVATE (object);
+
+ switch (prop_id) {
+ case PROP_DEVICE:
+ g_value_set_string (value, priv->device);
+ break;
+ case PROP_SUBSYS:
+ g_value_set_uint (value, priv->subsys);
+ break;
+ case PROP_TYPE:
+ g_value_set_uint (value, priv->ptype);
+ break;
+ case PROP_CARRIER_DETECT:
+ g_value_set_boolean (value, priv->carrier_detect);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+finalize (GObject *object)
+{
+ MMPortPrivate *priv = MM_PORT_GET_PRIVATE (object);
+
+ g_free (priv->device);
+
+ G_OBJECT_CLASS (mm_port_parent_class)->finalize (object);
+}
+
+static void
+mm_port_class_init (MMPortClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMPortPrivate));
+
+ /* Virtual methods */
+ object_class->constructor = constructor;
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+ object_class->finalize = finalize;
+
+ g_object_class_install_property
+ (object_class, PROP_DEVICE,
+ g_param_spec_string (MM_PORT_DEVICE,
+ "Device",
+ "Device",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property
+ (object_class, PROP_SUBSYS,
+ g_param_spec_uint (MM_PORT_SUBSYS,
+ "Subsystem",
+ "Subsystem",
+ MM_PORT_SUBSYS_UNKNOWN,
+ MM_PORT_SUBSYS_LAST,
+ MM_PORT_SUBSYS_UNKNOWN,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property
+ (object_class, PROP_TYPE,
+ g_param_spec_uint (MM_PORT_TYPE,
+ "Type",
+ "Type",
+ MM_PORT_TYPE_UNKNOWN,
+ MM_PORT_TYPE_LAST,
+ MM_PORT_TYPE_UNKNOWN,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property
+ (object_class, PROP_CARRIER_DETECT,
+ g_param_spec_boolean (MM_PORT_CARRIER_DETECT,
+ "Carrier Detect",
+ "Has Carrier Detect",
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+}
diff --git a/src/mm-port.h b/src/mm-port.h
new file mode 100644
index 00000000..339b91ea
--- /dev/null
+++ b/src/mm-port.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_PORT_H
+#define MM_PORT_H
+
+#include <glib.h>
+#include <glib/gtypes.h>
+#include <glib-object.h>
+
+typedef enum {
+ MM_PORT_SUBSYS_UNKNOWN = 0x0,
+ MM_PORT_SUBSYS_TTY,
+ MM_PORT_SUBSYS_NET,
+
+ MM_PORT_SUBSYS_LAST = MM_PORT_SUBSYS_NET
+} MMPortSubsys;
+
+typedef enum {
+ MM_PORT_TYPE_UNKNOWN = 0x0,
+ MM_PORT_TYPE_PRIMARY,
+ MM_PORT_TYPE_SECONDARY,
+ MM_PORT_TYPE_IGNORED,
+
+ MM_PORT_TYPE_LAST = MM_PORT_TYPE_IGNORED
+} MMPortType;
+
+#define MM_TYPE_PORT (mm_port_get_type ())
+#define MM_PORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PORT, MMPort))
+#define MM_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PORT, MMPortClass))
+#define MM_IS_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PORT))
+#define MM_IS_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PORT))
+#define MM_PORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PORT, MMPortClass))
+
+#define MM_PORT_DEVICE "device"
+#define MM_PORT_SUBSYS "subsys"
+#define MM_PORT_TYPE "type"
+#define MM_PORT_CARRIER_DETECT "carrier-detect"
+
+typedef struct _MMPort MMPort;
+typedef struct _MMPortClass MMPortClass;
+
+struct _MMPort {
+ GObject parent;
+};
+
+struct _MMPortClass {
+ GObjectClass parent;
+};
+
+GType mm_port_get_type (void);
+
+const char * mm_port_get_device (MMPort *self);
+
+MMPortSubsys mm_port_get_subsys (MMPort *self);
+
+MMPortType mm_port_get_port_type (MMPort *self);
+
+gboolean mm_port_get_carrier_detect (MMPort *self);
+
+#endif /* MM_PORT_H */
+
diff --git a/src/mm-serial-parsers.c b/src/mm-serial-parsers.c
index 8e6b75b8..ae0c20da 100644
--- a/src/mm-serial-parsers.c
+++ b/src/mm-serial-parsers.c
@@ -87,6 +87,9 @@ mm_serial_parser_v0_parse (gpointer data,
g_return_val_if_fail (parser != NULL, FALSE);
g_return_val_if_fail (response != NULL, FALSE);
+ if (G_UNLIKELY (!response->len || !strlen (response->str)))
+ return FALSE;
+
found = g_regex_match_full (parser->generic_response, response->str, response->len, 0, 0, &match_info, NULL);
if (found) {
str = g_match_info_fetch (match_info, 1);
@@ -205,7 +208,10 @@ mm_serial_parser_v1_parse (gpointer data,
g_return_val_if_fail (parser != NULL, FALSE);
g_return_val_if_fail (response != NULL, FALSE);
- /* First, check for successfule responses */
+ if (G_UNLIKELY (!response->len || !strlen (response->str)))
+ return FALSE;
+
+ /* First, check for successful responses */
found = g_regex_match_full (parser->regex_ok, response->str, response->len, 0, 0, NULL, NULL);
if (found)
diff --git a/src/mm-serial.c b/src/mm-serial-port.c
index 0301a592..26585e37 100644
--- a/src/mm-serial.c
+++ b/src/mm-serial-port.c
@@ -1,4 +1,18 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
#define _GNU_SOURCE /* for strcasestr() */
@@ -13,30 +27,28 @@
#include <sys/ioctl.h>
#include <string.h>
-#include "mm-serial.h"
+#include "mm-serial-port.h"
#include "mm-errors.h"
#include "mm-options.h"
-static gboolean mm_serial_queue_process (gpointer data);
+static gboolean mm_serial_port_queue_process (gpointer data);
-G_DEFINE_TYPE (MMSerial, mm_serial, G_TYPE_OBJECT)
+G_DEFINE_TYPE (MMSerialPort, mm_serial_port, MM_TYPE_PORT)
enum {
PROP_0,
- PROP_DEVICE,
PROP_BAUD,
PROP_BITS,
PROP_PARITY,
PROP_STOPBITS,
PROP_SEND_DELAY,
- PROP_CARRIER_DETECT,
LAST_PROP
};
#define SERIAL_BUF_SIZE 2048
-#define MM_SERIAL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_SERIAL, MMSerialPrivate))
+#define MM_SERIAL_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_SERIAL_PORT, MMSerialPortPrivate))
typedef struct {
int fd;
@@ -54,18 +66,16 @@ typedef struct {
struct termios old_t;
- char *device;
guint baud;
guint bits;
char parity;
guint stopbits;
guint64 send_delay;
- gboolean carrier_detect;
guint queue_schedule;
guint watch_id;
guint timeout_id;
-} MMSerialPrivate;
+} MMSerialPortPrivate;
typedef struct {
GRegex *regex;
@@ -74,32 +84,24 @@ typedef struct {
GDestroyNotify notify;
} MMUnsolicitedMsgHandler;
-const char *
-mm_serial_get_device (MMSerial *serial)
-{
- g_return_val_if_fail (MM_IS_SERIAL (serial), NULL);
-
- return MM_SERIAL_GET_PRIVATE (serial)->device;
-}
-
static void
-mm_serial_set_cached_reply (MMSerial *self,
- const char *command,
- const char *reply)
+mm_serial_port_set_cached_reply (MMSerialPort *self,
+ const char *command,
+ const char *reply)
{
if (reply)
- g_hash_table_insert (MM_SERIAL_GET_PRIVATE (self)->reply_cache,
+ g_hash_table_insert (MM_SERIAL_PORT_GET_PRIVATE (self)->reply_cache,
g_strdup (command),
g_strdup (reply));
else
- g_hash_table_remove (MM_SERIAL_GET_PRIVATE (self)->reply_cache, command);
+ g_hash_table_remove (MM_SERIAL_PORT_GET_PRIVATE (self)->reply_cache, command);
}
static const char *
-mm_serial_get_cached_reply (MMSerial *self,
- const char *command)
+mm_serial_port_get_cached_reply (MMSerialPort *self,
+ const char *command)
{
- return (char *) g_hash_table_lookup (MM_SERIAL_GET_PRIVATE (self)->reply_cache, command);
+ return (char *) g_hash_table_lookup (MM_SERIAL_PORT_GET_PRIVATE (self)->reply_cache, command);
}
static int
@@ -237,9 +239,9 @@ parse_stopbits (guint i)
}
static gboolean
-config_fd (MMSerial *self)
+config_fd (MMSerialPort *self)
{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
struct termio stbuf;
int speed;
int bits;
@@ -265,7 +267,8 @@ config_fd (MMSerial *self)
stbuf.c_cflag |= (speed | bits | CREAD | 0 | parity | stopbits);
if (ioctl (priv->fd, TCSETA, &stbuf) < 0) {
- g_warning ("(%s) cannot control device (errno %d)", priv->device, errno);
+ g_warning ("(%s) cannot control device (errno %d)",
+ mm_port_get_device (MM_PORT (self)), errno);
return FALSE;
}
@@ -273,7 +276,7 @@ config_fd (MMSerial *self)
}
static void
-serial_debug (const char *prefix, const char *buf, int len)
+serial_debug (MMSerialPort *self, const char *prefix, const char *buf, int len)
{
static GString *debug = NULL;
const char *s;
@@ -305,27 +308,27 @@ serial_debug (const char *prefix, const char *buf, int len)
}
g_string_append_c (debug, '\'');
- g_debug ("%s", debug->str);
+ g_debug ("(%s): %s", mm_port_get_device (MM_PORT (self)), debug->str);
g_string_truncate (debug, 0);
}
static gboolean
-mm_serial_send_command (MMSerial *self,
- const char *command,
- GError **error)
+mm_serial_port_send_command (MMSerialPort *self,
+ const char *command,
+ GError **error)
{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
const char *s;
int status;
int eagain_count = 1000;
- if (priv->fd == 0) {
+ if (priv->fd < 0) {
g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_SEND_FAILED,
"%s", "Sending command failed: device is not enabled");
return FALSE;
}
- if (mm_serial_is_connected (self)) {
+ if (mm_serial_port_is_connected (self)) {
g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_SEND_FAILED,
"%s", "Sending command failed: device is connected");
return FALSE;
@@ -337,7 +340,7 @@ mm_serial_send_command (MMSerial *self,
if (command[strlen (command)] != '\r')
g_string_append_c (priv->command, '\r');
- serial_debug ("-->", priv->command->str, -1);
+ serial_debug (self, "-->", priv->command->str, -1);
s = priv->command->str;
while (*s) {
@@ -374,9 +377,9 @@ typedef struct {
} MMQueueData;
static void
-mm_serial_schedule_queue_process (MMSerial *self)
+mm_serial_port_schedule_queue_process (MMSerialPort *self)
{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
GSource *source;
if (priv->queue_schedule)
@@ -384,16 +387,16 @@ mm_serial_schedule_queue_process (MMSerial *self)
return;
source = g_idle_source_new ();
- g_source_set_closure (source, g_cclosure_new_object (G_CALLBACK (mm_serial_queue_process), G_OBJECT (self)));
+ g_source_set_closure (source, g_cclosure_new_object (G_CALLBACK (mm_serial_port_queue_process), G_OBJECT (self)));
g_source_attach (source, NULL);
priv->queue_schedule = g_source_get_id (source);
g_source_unref (source);
}
static void
-mm_serial_got_response (MMSerial *self, GError *error)
+mm_serial_port_got_response (MMSerialPort *self, GError *error)
{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
MMQueueData *info;
if (priv->timeout_id)
@@ -402,7 +405,7 @@ mm_serial_got_response (MMSerial *self, GError *error)
info = (MMQueueData *) g_queue_pop_head (priv->queue);
if (info) {
if (info->cached && !error)
- mm_serial_set_cached_reply (self, info->command, priv->response->str);
+ mm_serial_port_set_cached_reply (self, info->command, priv->response->str);
if (info->callback)
info->callback (self, priv->response, error, info->user_data);
@@ -416,14 +419,14 @@ mm_serial_got_response (MMSerial *self, GError *error)
g_string_truncate (priv->response, 0);
if (!g_queue_is_empty (priv->queue))
- mm_serial_schedule_queue_process (self);
+ mm_serial_port_schedule_queue_process (self);
}
static gboolean
-mm_serial_timed_out (gpointer data)
+mm_serial_port_timed_out (gpointer data)
{
- MMSerial *self = MM_SERIAL (data);
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMSerialPort *self = MM_SERIAL_PORT (data);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
GError *error;
priv->timeout_id = 0;
@@ -434,16 +437,16 @@ mm_serial_timed_out (gpointer data)
/* FIXME: This is not completely correct - if the response finally arrives and there's
some other command waiting for response right now, the other command will
get the output of the timed out command. Not sure what to do here. */
- mm_serial_got_response (self, error);
+ mm_serial_port_got_response (self, error);
return FALSE;
}
static gboolean
-mm_serial_queue_process (gpointer data)
+mm_serial_port_queue_process (gpointer data)
{
- MMSerial *self = MM_SERIAL (data);
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMSerialPort *self = MM_SERIAL_PORT (data);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
MMQueueData *info;
GError *error = NULL;
@@ -454,41 +457,41 @@ mm_serial_queue_process (gpointer data)
return FALSE;
if (info->cached) {
- const char *cached = mm_serial_get_cached_reply (self, info->command);
+ const char *cached = mm_serial_port_get_cached_reply (self, info->command);
if (cached) {
g_string_append (priv->response, cached);
- mm_serial_got_response (self, NULL);
+ mm_serial_port_got_response (self, NULL);
return FALSE;
}
}
- if (mm_serial_send_command (self, info->command, &error)) {
+ if (mm_serial_port_send_command (self, info->command, &error)) {
GSource *source;
source = g_timeout_source_new (info->timeout);
- g_source_set_closure (source, g_cclosure_new_object (G_CALLBACK (mm_serial_timed_out), G_OBJECT (self)));
+ g_source_set_closure (source, g_cclosure_new_object (G_CALLBACK (mm_serial_port_timed_out), G_OBJECT (self)));
g_source_attach (source, NULL);
priv->timeout_id = g_source_get_id (source);
g_source_unref (source);
} else {
- mm_serial_got_response (self, error);
+ mm_serial_port_got_response (self, error);
}
return FALSE;
}
void
-mm_serial_add_unsolicited_msg_handler (MMSerial *self,
- GRegex *regex,
- MMSerialUnsolicitedMsgFn callback,
- gpointer user_data,
- GDestroyNotify notify)
+mm_serial_port_add_unsolicited_msg_handler (MMSerialPort *self,
+ GRegex *regex,
+ MMSerialUnsolicitedMsgFn callback,
+ gpointer user_data,
+ GDestroyNotify notify)
{
MMUnsolicitedMsgHandler *handler;
- MMSerialPrivate *priv;
+ MMSerialPortPrivate *priv;
- g_return_if_fail (MM_IS_SERIAL (self));
+ g_return_if_fail (MM_IS_SERIAL_PORT (self));
g_return_if_fail (regex != NULL);
handler = g_slice_new (MMUnsolicitedMsgHandler);
@@ -497,19 +500,19 @@ mm_serial_add_unsolicited_msg_handler (MMSerial *self,
handler->user_data = user_data;
handler->notify = notify;
- priv = MM_SERIAL_GET_PRIVATE (self);
+ priv = MM_SERIAL_PORT_GET_PRIVATE (self);
priv->unsolicited_msg_handlers = g_slist_append (priv->unsolicited_msg_handlers, handler);
}
void
-mm_serial_set_response_parser (MMSerial *self,
- MMSerialResponseParserFn fn,
- gpointer user_data,
- GDestroyNotify notify)
+mm_serial_port_set_response_parser (MMSerialPort *self,
+ MMSerialResponseParserFn fn,
+ gpointer user_data,
+ GDestroyNotify notify)
{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
- g_return_if_fail (MM_IS_SERIAL (self));
+ g_return_if_fail (MM_IS_SERIAL_PORT (self));
if (priv->response_parser_notify)
priv->response_parser_notify (priv->response_parser_user_data);
@@ -535,10 +538,10 @@ remove_eval_cb (const GMatchInfo *match_info,
}
static void
-parse_unsolicited_messages (MMSerial *self,
+parse_unsolicited_messages (MMSerialPort *self,
GString *response)
{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
GSList *iter;
for (iter = priv->unsolicited_msg_handlers; iter; iter = iter->next) {
@@ -572,11 +575,11 @@ parse_unsolicited_messages (MMSerial *self,
}
static gboolean
-parse_response (MMSerial *self,
+parse_response (MMSerialPort *self,
GString *response,
GError **error)
{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
g_return_val_if_fail (priv->response_parser_fn != NULL, FALSE);
@@ -590,15 +593,15 @@ data_available (GIOChannel *source,
GIOCondition condition,
gpointer data)
{
- MMSerial *self = MM_SERIAL (data);
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMSerialPort *self = MM_SERIAL_PORT (data);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
char buf[SERIAL_BUF_SIZE + 1];
gsize bytes_read;
GIOStatus status;
if (condition & G_IO_HUP) {
g_string_truncate (priv->response, 0);
- mm_serial_close (self);
+ mm_serial_port_close (self);
return FALSE;
}
@@ -617,63 +620,83 @@ data_available (GIOChannel *source,
err = NULL;
}
+ /* If no bytes read, just let g_io_channel wait for more data */
+ if (bytes_read == 0)
+ break;
+
if (bytes_read > 0) {
- serial_debug ("<--", buf, bytes_read);
+ serial_debug (self, "<--", buf, bytes_read);
g_string_append_len (priv->response, buf, bytes_read);
}
/* Make sure the string doesn't grow too long */
if (priv->response->len > SERIAL_BUF_SIZE) {
g_warning ("%s (%s): response buffer filled before repsonse received",
- G_STRFUNC, mm_serial_get_device (self));
+ G_STRFUNC, mm_port_get_device (MM_PORT (self)));
g_string_erase (priv->response, 0, (SERIAL_BUF_SIZE / 2));
}
if (parse_response (self, priv->response, &err))
- mm_serial_got_response (self, err);
+ mm_serial_port_got_response (self, err);
} while (bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN);
return TRUE;
}
gboolean
-mm_serial_open (MMSerial *self, GError **error)
+mm_serial_port_open (MMSerialPort *self, GError **error)
{
- MMSerialPrivate *priv;
+ MMSerialPortPrivate *priv;
+ char *devfile;
+ const char *device;
- g_return_val_if_fail (MM_IS_SERIAL (self), FALSE);
+ g_return_val_if_fail (MM_IS_SERIAL_PORT (self), FALSE);
- priv = MM_SERIAL_GET_PRIVATE (self);
+ priv = MM_SERIAL_PORT_GET_PRIVATE (self);
- if (priv->fd)
+ if (priv->fd >= 0)
/* Already open */
return TRUE;
- g_debug ("(%s) opening serial device...", priv->device);
- priv->fd = open (priv->device, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
+ device = mm_port_get_device (MM_PORT (self));
+
+ g_message ("(%s) opening serial device...", device);
+ devfile = g_strdup_printf ("/dev/%s", device);
+ priv->fd = open (devfile, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
+ g_free (devfile);
if (priv->fd < 0) {
g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_OPEN_FAILED,
- "Could not open serial device %s: %s", priv->device, strerror (errno));
+ "Could not open serial device %s: %s", device, strerror (errno));
+ return FALSE;
+ }
+
+ if (ioctl (priv->fd, TIOCEXCL) < 0) {
+ g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_OPEN_FAILED,
+ "Could not lock serial device %s: %s", device, strerror (errno));
+ close (priv->fd);
+ priv->fd = -1;
return FALSE;
}
if (ioctl (priv->fd, TCGETA, &priv->old_t) < 0) {
g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_OPEN_FAILED,
- "Could not open serial device %s: %s", priv->device, strerror (errno));
+ "Could not open serial device %s: %s", device, strerror (errno));
close (priv->fd);
+ priv->fd = -1;
return FALSE;
}
if (!config_fd (self)) {
g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_OPEN_FAILED,
- "Could not open serial device %s: %s", priv->device, strerror (errno));
+ "Could not open serial device %s: %s", device, strerror (errno));
close (priv->fd);
- priv->fd = 0;
+ priv->fd = -1;
return FALSE;
}
priv->channel = g_io_channel_unix_new (priv->fd);
+ g_io_channel_set_encoding (priv->channel, NULL, NULL);
priv->watch_id = g_io_add_watch (priv->channel,
G_IO_IN | G_IO_ERR | G_IO_HUP,
data_available, self);
@@ -682,16 +705,16 @@ mm_serial_open (MMSerial *self, GError **error)
}
void
-mm_serial_close (MMSerial *self)
+mm_serial_port_close (MMSerialPort *self)
{
- MMSerialPrivate *priv;
+ MMSerialPortPrivate *priv;
- g_return_if_fail (MM_IS_SERIAL (self));
+ g_return_if_fail (MM_IS_SERIAL_PORT (self));
- priv = MM_SERIAL_GET_PRIVATE (self);
+ priv = MM_SERIAL_PORT_GET_PRIVATE (self);
- if (priv->fd) {
- g_message ("Closing device '%s'", priv->device);
+ if (priv->fd >= 0) {
+ g_message ("(%s) closing serial device...", mm_port_get_device (MM_PORT (self)));
if (priv->channel) {
g_source_remove (priv->watch_id);
@@ -702,22 +725,22 @@ mm_serial_close (MMSerial *self)
ioctl (priv->fd, TCSETA, &priv->old_t);
close (priv->fd);
- priv->fd = 0;
+ priv->fd = -1;
}
}
static void
-internal_queue_command (MMSerial *self,
+internal_queue_command (MMSerialPort *self,
const char *command,
gboolean cached,
guint32 timeout_seconds,
MMSerialResponseFn callback,
gpointer user_data)
{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
MMQueueData *info;
- g_return_if_fail (MM_IS_SERIAL (self));
+ g_return_if_fail (MM_IS_SERIAL_PORT (self));
g_return_if_fail (command != NULL);
info = g_slice_new0 (MMQueueData);
@@ -729,58 +752,60 @@ internal_queue_command (MMSerial *self,
/* Clear the cached value for this command if not asking for cached value */
if (!cached)
- mm_serial_set_cached_reply (self, command, NULL);
+ mm_serial_port_set_cached_reply (self, command, NULL);
g_queue_push_tail (priv->queue, info);
if (g_queue_get_length (priv->queue) == 1)
- mm_serial_schedule_queue_process (self);
+ mm_serial_port_schedule_queue_process (self);
}
void
-mm_serial_queue_command (MMSerial *self,
- const char *command,
- guint32 timeout_seconds,
- MMSerialResponseFn callback,
- gpointer user_data)
+mm_serial_port_queue_command (MMSerialPort *self,
+ const char *command,
+ guint32 timeout_seconds,
+ MMSerialResponseFn callback,
+ gpointer user_data)
{
internal_queue_command (self, command, FALSE, timeout_seconds, callback, user_data);
}
void
-mm_serial_queue_command_cached (MMSerial *self,
- const char *command,
- guint32 timeout_seconds,
- MMSerialResponseFn callback,
- gpointer user_data)
+mm_serial_port_queue_command_cached (MMSerialPort *self,
+ const char *command,
+ guint32 timeout_seconds,
+ MMSerialResponseFn callback,
+ gpointer user_data)
{
internal_queue_command (self, command, TRUE, timeout_seconds, callback, user_data);
}
typedef struct {
- MMSerial *serial;
+ MMSerialPort *port;
speed_t current_speed;
MMSerialFlashFn callback;
gpointer user_data;
} FlashInfo;
static speed_t
-get_speed (MMSerial *self)
+get_speed (MMSerialPort *self)
{
struct termios options;
- tcgetattr (MM_SERIAL_GET_PRIVATE (self)->fd, &options);
+ memset (&options, 0, sizeof (struct termios));
+ tcgetattr (MM_SERIAL_PORT_GET_PRIVATE (self)->fd, &options);
return cfgetospeed (&options);
}
static void
-set_speed (MMSerial *self, speed_t speed)
+set_speed (MMSerialPort *self, speed_t speed)
{
struct termios options;
int fd;
- fd = MM_SERIAL_GET_PRIVATE (self)->fd;
+ fd = MM_SERIAL_PORT_GET_PRIVATE (self)->fd;
+ memset (&options, 0, sizeof (struct termios));
tcgetattr (fd, &options);
cfsetispeed (&options, speed);
@@ -795,7 +820,7 @@ flash_done (gpointer data)
{
FlashInfo *info = (FlashInfo *) data;
- info->callback (info->serial, info->user_data);
+ info->callback (info->port, info->user_data);
g_slice_free (FlashInfo, info);
}
@@ -805,25 +830,25 @@ flash_do (gpointer data)
{
FlashInfo *info = (FlashInfo *) data;
- set_speed (info->serial, info->current_speed);
+ set_speed (info->port, info->current_speed);
return FALSE;
}
guint
-mm_serial_flash (MMSerial *self,
- guint32 flash_time,
- MMSerialFlashFn callback,
- gpointer user_data)
+mm_serial_port_flash (MMSerialPort *self,
+ guint32 flash_time,
+ MMSerialFlashFn callback,
+ gpointer user_data)
{
FlashInfo *info;
guint id;
- g_return_val_if_fail (MM_IS_SERIAL (self), 0);
+ g_return_val_if_fail (MM_IS_SERIAL_PORT (self), 0);
g_return_val_if_fail (callback != NULL, 0);
info = g_slice_new0 (FlashInfo);
- info->serial = self;
+ info->port = self;
info->current_speed = get_speed (self);
info->callback = callback;
info->user_data = user_data;
@@ -840,19 +865,19 @@ mm_serial_flash (MMSerial *self,
}
gboolean
-mm_serial_is_connected (MMSerial *self)
+mm_serial_port_is_connected (MMSerialPort *self)
{
- MMSerialPrivate *priv;
+ MMSerialPortPrivate *priv;
int mcs = 0;
- g_return_val_if_fail (MM_IS_SERIAL (self), FALSE);
+ g_return_val_if_fail (MM_IS_SERIAL_PORT (self), FALSE);
- priv = MM_SERIAL_GET_PRIVATE (self);
+ priv = MM_SERIAL_PORT_GET_PRIVATE (self);
- if (!priv->carrier_detect)
+ if (!mm_port_get_carrier_detect (MM_PORT (self)))
return FALSE;
- if (priv->fd == 0)
+ if (priv->fd < 0)
return FALSE;
if (ioctl (priv->fd, TIOCMGET, &mcs) < 0)
@@ -863,61 +888,42 @@ mm_serial_is_connected (MMSerial *self)
/*****************************************************************************/
+MMSerialPort *
+mm_serial_port_new (const char *name, MMPortType ptype)
+{
+ return MM_SERIAL_PORT (g_object_new (MM_TYPE_SERIAL_PORT,
+ MM_PORT_DEVICE, name,
+ MM_PORT_SUBSYS, MM_PORT_SUBSYS_TTY,
+ MM_PORT_TYPE, ptype,
+ NULL));
+}
+
static void
-mm_serial_init (MMSerial *self)
+mm_serial_port_init (MMSerialPort *self)
{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
priv->reply_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ priv->fd = -1;
priv->baud = 57600;
priv->bits = 8;
priv->parity = 'n';
priv->stopbits = 1;
priv->send_delay = 1000;
- priv->carrier_detect = TRUE;
priv->queue = g_queue_new ();
priv->command = g_string_new_len ("AT", SERIAL_BUF_SIZE);
priv->response = g_string_sized_new (SERIAL_BUF_SIZE);
}
-static GObject*
-constructor (GType type,
- guint n_construct_params,
- GObjectConstructParam *construct_params)
-{
- GObject *object;
- MMSerialPrivate *priv;
-
- object = G_OBJECT_CLASS (mm_serial_parent_class)->constructor (type,
- n_construct_params,
- construct_params);
- if (!object)
- return NULL;
-
- priv = MM_SERIAL_GET_PRIVATE (object);
-
- if (!priv->device) {
- g_warning ("No device provided");
- g_object_unref (object);
- return NULL;
- }
-
- return object;
-}
-
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (object);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (object);
switch (prop_id) {
- case PROP_DEVICE:
- /* Construct only */
- priv->device = g_value_dup_string (value);
- break;
case PROP_BAUD:
priv->baud = g_value_get_uint (value);
break;
@@ -933,9 +939,6 @@ set_property (GObject *object, guint prop_id,
case PROP_SEND_DELAY:
priv->send_delay = g_value_get_uint64 (value);
break;
- case PROP_CARRIER_DETECT:
- priv->carrier_detect = g_value_get_boolean (value);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -946,12 +949,9 @@ static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (object);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (object);
switch (prop_id) {
- case PROP_DEVICE:
- g_value_set_string (value, priv->device);
- break;
case PROP_BAUD:
g_value_set_uint (value, priv->baud);
break;
@@ -967,9 +967,6 @@ get_property (GObject *object, guint prop_id,
case PROP_SEND_DELAY:
g_value_set_uint64 (value, priv->send_delay);
break;
- case PROP_CARRIER_DETECT:
- g_value_set_boolean (value, priv->carrier_detect);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -979,16 +976,15 @@ get_property (GObject *object, guint prop_id,
static void
finalize (GObject *object)
{
- MMSerial *self = MM_SERIAL (object);
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
+ MMSerialPort *self = MM_SERIAL_PORT (object);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
- mm_serial_close (self);
+ mm_serial_port_close (self);
g_hash_table_destroy (priv->reply_cache);
g_queue_free (priv->queue);
g_string_free (priv->command, TRUE);
g_string_free (priv->response, TRUE);
- g_free (priv->device);
while (priv->unsolicited_msg_handlers) {
MMUnsolicitedMsgHandler *handler = (MMUnsolicitedMsgHandler *) priv->unsolicited_msg_handlers->data;
@@ -1005,34 +1001,25 @@ finalize (GObject *object)
if (priv->response_parser_notify)
priv->response_parser_notify (priv->response_parser_user_data);
- G_OBJECT_CLASS (mm_serial_parent_class)->finalize (object);
+ G_OBJECT_CLASS (mm_serial_port_parent_class)->finalize (object);
}
static void
-mm_serial_class_init (MMSerialClass *klass)
+mm_serial_port_class_init (MMSerialPortClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- g_type_class_add_private (object_class, sizeof (MMSerialPrivate));
+ g_type_class_add_private (object_class, sizeof (MMSerialPortPrivate));
/* 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_DEVICE,
- g_param_spec_string (MM_SERIAL_DEVICE,
- "Device",
- "Serial device",
- NULL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
- g_object_class_install_property
(object_class, PROP_BAUD,
- g_param_spec_uint (MM_SERIAL_BAUD,
+ g_param_spec_uint (MM_SERIAL_PORT_BAUD,
"Baud",
"Baud rate",
0, G_MAXUINT, 57600,
@@ -1040,7 +1027,7 @@ mm_serial_class_init (MMSerialClass *klass)
g_object_class_install_property
(object_class, PROP_BITS,
- g_param_spec_uint (MM_SERIAL_BITS,
+ g_param_spec_uint (MM_SERIAL_PORT_BITS,
"Bits",
"Bits",
5, 8, 8,
@@ -1048,7 +1035,7 @@ mm_serial_class_init (MMSerialClass *klass)
g_object_class_install_property
(object_class, PROP_PARITY,
- g_param_spec_char (MM_SERIAL_PARITY,
+ g_param_spec_char (MM_SERIAL_PORT_PARITY,
"Parity",
"Parity",
'E', 'o', 'n',
@@ -1056,7 +1043,7 @@ mm_serial_class_init (MMSerialClass *klass)
g_object_class_install_property
(object_class, PROP_STOPBITS,
- g_param_spec_uint (MM_SERIAL_STOPBITS,
+ g_param_spec_uint (MM_SERIAL_PORT_STOPBITS,
"Stopbits",
"Stopbits",
1, 2, 1,
@@ -1064,17 +1051,9 @@ mm_serial_class_init (MMSerialClass *klass)
g_object_class_install_property
(object_class, PROP_SEND_DELAY,
- g_param_spec_uint64 (MM_SERIAL_SEND_DELAY,
+ g_param_spec_uint64 (MM_SERIAL_PORT_SEND_DELAY,
"SendDelay",
"Send delay",
0, G_MAXUINT64, 0,
G_PARAM_READWRITE));
-
- g_object_class_install_property
- (object_class, PROP_CARRIER_DETECT,
- g_param_spec_boolean (MM_SERIAL_CARRIER_DETECT,
- "CarrierDetect",
- "Has carrier detect",
- TRUE,
- G_PARAM_READWRITE));
}
diff --git a/src/mm-serial-port.h b/src/mm-serial-port.h
new file mode 100644
index 00000000..0f4497a2
--- /dev/null
+++ b/src/mm-serial-port.h
@@ -0,0 +1,105 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_SERIAL_PORT_H
+#define MM_SERIAL_PORT_H
+
+#include <glib.h>
+#include <glib/gtypes.h>
+#include <glib-object.h>
+
+#include "mm-port.h"
+
+#define MM_TYPE_SERIAL_PORT (mm_serial_port_get_type ())
+#define MM_SERIAL_PORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SERIAL_PORT, MMSerialPort))
+#define MM_SERIAL_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SERIAL_PORT, MMSerialPortClass))
+#define MM_IS_SERIAL_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SERIAL_PORT))
+#define MM_IS_SERIAL_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SERIAL_PORT))
+#define MM_SERIAL_PORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SERIAL_PORT, MMSerialPortClass))
+
+#define MM_SERIAL_PORT_BAUD "baud"
+#define MM_SERIAL_PORT_BITS "bits"
+#define MM_SERIAL_PORT_PARITY "parity"
+#define MM_SERIAL_PORT_STOPBITS "stopbits"
+#define MM_SERIAL_PORT_SEND_DELAY "send-delay"
+
+typedef struct _MMSerialPort MMSerialPort;
+typedef struct _MMSerialPortClass MMSerialPortClass;
+
+typedef gboolean (*MMSerialResponseParserFn) (gpointer user_data,
+ GString *response,
+ GError **error);
+
+typedef void (*MMSerialUnsolicitedMsgFn) (MMSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data);
+
+typedef void (*MMSerialResponseFn) (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data);
+
+typedef void (*MMSerialFlashFn) (MMSerialPort *port,
+ gpointer user_data);
+
+struct _MMSerialPort {
+ MMPort parent;
+};
+
+struct _MMSerialPortClass {
+ MMPortClass parent;
+};
+
+GType mm_serial_port_get_type (void);
+
+MMSerialPort *mm_serial_port_new (const char *name, MMPortType ptype);
+
+void mm_serial_port_add_unsolicited_msg_handler (MMSerialPort *self,
+ GRegex *regex,
+ MMSerialUnsolicitedMsgFn callback,
+ gpointer user_data,
+ GDestroyNotify notify);
+
+void mm_serial_port_set_response_parser (MMSerialPort *self,
+ MMSerialResponseParserFn fn,
+ gpointer user_data,
+ GDestroyNotify notify);
+
+gboolean mm_serial_port_open (MMSerialPort *self,
+ GError **error);
+
+void mm_serial_port_close (MMSerialPort *self);
+void mm_serial_port_queue_command (MMSerialPort *self,
+ const char *command,
+ guint32 timeout_seconds,
+ MMSerialResponseFn callback,
+ gpointer user_data);
+
+void mm_serial_port_queue_command_cached (MMSerialPort *self,
+ const char *command,
+ guint32 timeout_seconds,
+ MMSerialResponseFn callback,
+ gpointer user_data);
+
+guint mm_serial_port_flash (MMSerialPort *self,
+ guint32 flash_time,
+ MMSerialFlashFn callback,
+ gpointer user_data);
+
+gboolean mm_serial_port_is_connected (MMSerialPort *self);
+
+#endif /* MM_SERIAL_PORT_H */
+
diff --git a/src/mm-serial.h b/src/mm-serial.h
deleted file mode 100644
index e3479eed..00000000
--- a/src/mm-serial.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-
-#ifndef MM_SERIAL_H
-#define MM_SERIAL_H
-
-#include <glib.h>
-#include <glib/gtypes.h>
-#include <glib-object.h>
-
-#define MM_TYPE_SERIAL (mm_serial_get_type ())
-#define MM_SERIAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SERIAL, MMSerial))
-#define MM_SERIAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SERIAL, MMSerialClass))
-#define MM_IS_SERIAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SERIAL))
-#define MM_IS_SERIAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SERIAL))
-#define MM_SERIAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SERIAL, MMSerialClass))
-
-#define MM_SERIAL_DEVICE "serial-device"
-#define MM_SERIAL_BAUD "baud"
-#define MM_SERIAL_BITS "bits"
-#define MM_SERIAL_PARITY "parity"
-#define MM_SERIAL_STOPBITS "stopbits"
-#define MM_SERIAL_SEND_DELAY "send-delay"
-#define MM_SERIAL_CARRIER_DETECT "carrier-detect"
-
-typedef struct _MMSerial MMSerial;
-typedef struct _MMSerialClass MMSerialClass;
-
-typedef gboolean (*MMSerialResponseParserFn) (gpointer user_data,
- GString *response,
- GError **error);
-
-typedef void (*MMSerialUnsolicitedMsgFn) (MMSerial *serial,
- GMatchInfo *match_info,
- gpointer user_data);
-
-typedef void (*MMSerialResponseFn) (MMSerial *serial,
- GString *response,
- GError *error,
- gpointer user_data);
-
-typedef void (*MMSerialFlashFn) (MMSerial *serial,
- gpointer user_data);
-
-struct _MMSerial {
- GObject parent;
-};
-
-struct _MMSerialClass {
- GObjectClass parent;
-};
-
-GType mm_serial_get_type (void);
-
-void mm_serial_add_unsolicited_msg_handler (MMSerial *self,
- GRegex *regex,
- MMSerialUnsolicitedMsgFn callback,
- gpointer user_data,
- GDestroyNotify notify);
-
-void mm_serial_set_response_parser (MMSerial *self,
- MMSerialResponseParserFn fn,
- gpointer user_data,
- GDestroyNotify notify);
-
-gboolean mm_serial_open (MMSerial *self,
- GError **error);
-
-void mm_serial_close (MMSerial *self);
-void mm_serial_queue_command (MMSerial *self,
- const char *command,
- guint32 timeout_seconds,
- MMSerialResponseFn callback,
- gpointer user_data);
-
-void mm_serial_queue_command_cached (MMSerial *self,
- const char *command,
- guint32 timeout_seconds,
- MMSerialResponseFn callback,
- gpointer user_data);
-
-guint mm_serial_flash (MMSerial *self,
- guint32 flash_time,
- MMSerialFlashFn callback,
- gpointer user_data);
-
-gboolean mm_serial_is_connected (MMSerial *self);
-const char *mm_serial_get_device (MMSerial *self);
-
-#endif /* MM_SERIAL_H */