aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2009-06-18 14:25:30 -0400
committerDan Williams <dcbw@redhat.com>2009-06-18 14:25:30 -0400
commit924814c101da42fcb53005691d136852653f0eae (patch)
tree0ddc83d1c16b323f2962125640fd8ef0d6a0ed55 /src
parent0555cc1824aabbdda77cf1440c4e7be4ef8cc69e (diff)
udev: move device probing and detection to udev
Get rid of dependency on HAL, using libgudev instead. Fix up the plugin API to no longer use either HAL or udev defines, but let plugins use whatever mechanism they want for getting more information out of the device given the subsystem and device node name. Modems are now defined as "master" devices which "own" a one or more ports. A port could be a serial tty device or a network device or whatever. The plugin figures out whether it supports a given port or not and then assigns it to a new or existing modem. Modems now have a 'valid' property that should be set to TRUE when the modem has enough ports to operate correctly. For devices (ex. 'hso') that use a network device for data transfer, the modem would need to grab at least one TTY and the network device associated with that physical device to be 'valid'. Also move the generic modem support code to a plugin like other modem plugins, and change the I-support-this-device mechanism to return a number indicating the level of support. For example, the generic plugin would return a quite low number if the device indicates via probing that it can do GSM or CDMA, but a more specific plugin can indicate better support for the device, and thus the more specific plugin would win control.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am22
-rw-r--r--src/main.c93
-rw-r--r--src/mm-generic-cdma.c217
-rw-r--r--src/mm-generic-cdma.h17
-rw-r--r--src/mm-generic-gsm.c457
-rw-r--r--src/mm-generic-gsm.h17
-rw-r--r--src/mm-manager.c376
-rw-r--r--src/mm-manager.h6
-rw-r--r--src/mm-modem.c97
-rw-r--r--src/mm-modem.h54
-rw-r--r--src/mm-plugin.c48
-rw-r--r--src/mm-plugin.h58
-rw-r--r--src/mm-serial-port.c1107
-rw-r--r--src/mm-serial-port.h114
-rw-r--r--src/mm-serial.c1024
-rw-r--r--src/mm-serial.h80
16 files changed, 2192 insertions, 1595 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index d6d4e73f..e1557341 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,27 +2,35 @@ 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-serial.c \
+ mm-serial.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 \
@@ -36,11 +44,7 @@ modem_manager_SOURCES = \
mm-options.c \
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.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..99257067 100644
--- a/src/main.c
+++ b/src/main.c
@@ -5,7 +5,6 @@
#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"
@@ -135,87 +134,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
@@ -249,21 +172,13 @@ 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);
g_main_loop_run (loop);
- hal_deinit (manager);
g_object_unref (manager);
g_object_unref (proxy);
dbus_g_connection_unref (bus);
diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c
index de8c916a..984b8aa8 100644
--- a/src/mm-generic-cdma.c
+++ b/src/mm-generic-cdma.c
@@ -16,25 +16,124 @@ 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;
} 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 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)
+ 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)
+{
+ MMGenericCdma *self = MM_GENERIC_CDMA (modem);
+
+ if (strcmp (subsys, "tty"))
+ return FALSE;
+
+ return !!mm_serial_get_port (MM_SERIAL (self), name);
+}
+
+static gboolean
+grab_port (MMModem *modem,
+ const char *subsys,
+ const char *name,
+ GError **error)
+{
+ MMGenericCdma *self = MM_GENERIC_CDMA (modem);
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
+ MMSerialPortType ptype = MM_SERIAL_PORT_TYPE_IGNORED;
+ MMSerialPort *port;
+
+ if (strcmp (subsys, "tty"))
+ return FALSE;
+
+ if (!priv->primary)
+ ptype = MM_SERIAL_PORT_TYPE_PRIMARY;
+ else if (!priv->secondary)
+ ptype = MM_SERIAL_PORT_TYPE_SECONDARY;
+
+ port = mm_serial_add_port (MM_SERIAL (self), name, ptype);
+ g_object_set (G_OBJECT (port), MM_SERIAL_PORT_CARRIER_DETECT, FALSE, NULL);
+ mm_serial_port_set_response_parser (port,
+ mm_serial_parser_v1_parse,
+ mm_serial_parser_v1_new (),
+ mm_serial_parser_v1_destroy);
+
+ if (ptype == MM_SERIAL_PORT_TYPE_PRIMARY) {
+ priv->primary = port;
+ g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE);
+ check_valid (self);
+ } else if (ptype == MM_SERIAL_PORT_TYPE_SECONDARY)
+ priv->secondary = port;
+
+ return TRUE;
+}
+
+static void
+release_port (MMModem *modem, const char *subsys, const char *name)
+{
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
+ MMSerialPort *port;
+
+ if (strcmp (subsys, "tty"))
+ return;
+
+ port = mm_serial_get_port (MM_SERIAL (modem), name);
+ if (!port)
+ return;
+
+ if (port == priv->primary) {
+ mm_serial_remove_port (MM_SERIAL (modem), port);
+ priv->primary = NULL;
+ }
+
+ if (port == priv->secondary) {
+ mm_serial_remove_port (MM_SERIAL (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 +148,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 +164,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 +180,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 +218,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 +239,17 @@ 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
-get_signal_quality_done (MMSerial *serial,
+get_signal_quality_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -182,10 +286,15 @@ 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);
}
/*****************************************************************************/
@@ -261,6 +370,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 +378,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,6 +450,9 @@ 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;
@@ -361,24 +474,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 +511,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->primary)
+ g_value_set_string (value, mm_serial_port_get_device (priv->primary));
+ 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 +569,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
diff --git a/src/mm-generic-cdma.h b/src/mm-generic-cdma.h
index 125b540a..c8d25518 100644
--- a/src/mm-generic-cdma.h
+++ b/src/mm-generic-cdma.h
@@ -6,12 +6,12 @@
#include "mm-modem.h"
#include "mm-serial.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;
@@ -23,7 +23,8 @@ typedef struct {
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 a566fb6e..3cf8ab8c 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,39 @@ typedef struct {
guint32 signal_quality;
guint32 cid;
+
+ MMSerialPort *primary;
+ MMSerialPort *secondary;
} 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 +120,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 +135,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 +169,113 @@ 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)
+ 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)
+{
+ MMGenericGsm *self = MM_GENERIC_GSM (modem);
+
+ if (strcmp (subsys, "tty"))
+ return FALSE;
+
+ return !!mm_serial_get_port (MM_SERIAL (self), name);
+}
+
+static gboolean
+grab_port (MMModem *modem,
+ const char *subsys,
+ const char *name,
+ GError **error)
+{
+ MMGenericGsm *self = MM_GENERIC_GSM (modem);
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ MMSerialPortType ptype = MM_SERIAL_PORT_TYPE_IGNORED;
+ MMSerialPort *port;
+ GRegex *regex;
+
+ if (strcmp (subsys, "tty"))
+ return FALSE;
+
+ if (!priv->primary)
+ ptype = MM_SERIAL_PORT_TYPE_PRIMARY;
+ else if (!priv->secondary)
+ ptype = MM_SERIAL_PORT_TYPE_SECONDARY;
+
+ port = mm_serial_add_port (MM_SERIAL (self), name, ptype);
+ mm_serial_port_set_response_parser (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 (port, regex, reg_state_changed, self, NULL);
+ g_regex_unref (regex);
+
+
+ if (ptype == MM_SERIAL_PORT_TYPE_PRIMARY) {
+ priv->primary = port;
+ g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE);
+ check_valid (self);
+ } else if (ptype == MM_SERIAL_PORT_TYPE_SECONDARY)
+ priv->secondary = port;
+
+ return TRUE;
+}
+
+static void
+release_port (MMModem *modem, const char *subsys, const char *name)
+{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
+ MMSerialPort *port;
+
+ if (strcmp (subsys, "tty"))
+ return;
+
+ port = mm_serial_get_port (MM_SERIAL (modem), name);
+ if (!port)
+ return;
+
+ if (port == priv->primary) {
+ mm_serial_remove_port (MM_SERIAL (modem), port);
+ priv->primary = NULL;
+ check_valid (MM_GENERIC_GSM (modem));
+ }
+
+ if (port == priv->secondary) {
+ mm_serial_remove_port (MM_SERIAL (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,7 +289,7 @@ enable_done (MMSerial *serial,
}
static void
-init_done (MMSerial *serial,
+init_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -186,35 +300,35 @@ init_done (MMSerial *serial,
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);
+ mm_serial_port_queue_command (port, "+CFUN=1", 5, enable_done, user_data);
}
}
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);
+ mm_serial_port_queue_command (port, "Z E0 V1 X4 &C1 +CMEE=1", 3, init_done, user_data);
}
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);
+ mm_serial_port_queue_command (port, "+CFUN=0", 5, disable_done, user_data);
}
static void
@@ -223,6 +337,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 +348,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 +362,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 +382,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,10 +394,11 @@ 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
@@ -297,7 +414,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 +430,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 +444,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)
@@ -345,21 +462,21 @@ get_card_info (MMModemGsmCard *modem,
MMModemGsmCardInfoFn 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,
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 +495,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 +524,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 +554,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 +584,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 +621,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 */
@@ -618,24 +757,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_registration)
- get_registration_status (MM_SERIAL (info->modem), info);
+ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
+ if (priv->pending_registration)
+ get_registration_status (priv->primary, info);
return FALSE;
}
@@ -647,13 +789,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;
- MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (serial);
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
if (error) {
info->error = g_error_copy (error);
@@ -666,7 +808,7 @@ get_reg_status_done (MMSerial *serial,
int unsolicited, stat;
if (sscanf (response->str + 7, "%d,%d", &unsolicited, &stat)) {
- reg_status_updated (MM_GENERIC_GSM (serial), stat);
+ reg_status_updated (MM_GENERIC_GSM (info->modem), stat);
if (!unsolicited && priv->pending_registration) {
guint id;
@@ -687,19 +829,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 void
@@ -708,12 +850,13 @@ do_register (MMModemGsmNetwork *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);
- MM_GENERIC_GSM_GET_PRIVATE (modem)->pending_registration =
+ priv->pending_registration =
g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, 60,
pending_registration_timed_out,
info,
@@ -724,7 +867,7 @@ do_register (MMModemGsmNetwork *modem,
else
command = g_strdup ("+COPS=0,,");
- mm_serial_queue_command (MM_SERIAL (modem), command, 5, register_done, info);
+ mm_serial_port_queue_command (priv->primary, command, 5, register_done, info);
g_free (command);
}
@@ -758,7 +901,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)
@@ -774,17 +917,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);
@@ -796,6 +941,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));
@@ -816,12 +962,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);
}
@@ -831,13 +977,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
@@ -861,7 +1008,7 @@ destroy_scan_data (gpointer data)
}
static void
-scan_done (MMSerial *serial,
+scan_done (MMSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -880,8 +1027,13 @@ scan_done (MMSerial *serial,
reply += 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)
+ */
+ 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);
@@ -922,6 +1074,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),
@@ -929,13 +1082,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)
@@ -945,14 +1098,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)
@@ -1012,13 +1165,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)
@@ -1051,7 +1204,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;
}
@@ -1083,7 +1236,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
@@ -1092,23 +1245,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;
@@ -1127,7 +1282,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,
@@ -1142,23 +1298,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)
@@ -1181,16 +1340,33 @@ 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);
}
@@ -1441,6 +1617,9 @@ 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;
@@ -1484,16 +1663,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
@@ -1507,16 +1676,20 @@ 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:
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1530,21 +1703,30 @@ 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->primary)
+ g_value_set_string (value, mm_serial_port_get_device (priv->primary));
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;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1581,14 +1763,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);
@@ -1596,6 +1786,9 @@ 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);
}
GType
diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h
index 3f857365..a98afefa 100644
--- a/src/mm-generic-gsm.h
+++ b/src/mm-generic-gsm.h
@@ -6,12 +6,12 @@
#include "mm-modem-gsm-network.h"
#include "mm-serial.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_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;
@@ -23,8 +23,9 @@ typedef struct {
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);
diff --git a/src/mm-manager.c b/src/mm-manager.c
index a19c9446..beed08cc 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,9 +29,11 @@ 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;
} MMManagerPrivate;
@@ -147,169 +149,78 @@ mm_manager_new (DBusGConnection *bus)
return manager;
}
-static char *
-get_driver_name (LibHalContext *ctx, const char *udi)
-{
- char *parent_udi;
- char *driver = NULL;
-
- parent_udi = libhal_device_get_property_string (ctx, udi, "info.parent", NULL);
- if (parent_udi) {
- driver = libhal_device_get_property_string (ctx, parent_udi, "info.linux.driver", NULL);
- libhal_free_string (parent_udi);
- }
-
- return driver;
-}
-
-static MMModem *
-create_generic_modem (MMManager *manager, const char *udi)
-{
- 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;
-
- serial_device = libhal_device_get_property_string (priv->hal_ctx, udi, "serial.device", NULL);
- g_return_val_if_fail (serial_device != NULL, NULL);
-
- driver = get_driver_name (priv->hal_ctx, udi);
- g_return_val_if_fail (driver != NULL, NULL);
-
- 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;
-}
-
static void
-add_modem (MMManager *manager, const char *udi, MMModem *modem)
+remove_modem (MMManager *manager, MMModem *modem)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
+ char *device;
- g_hash_table_insert (priv->modems, g_strdup (udi), modem);
- dbus_g_connection_register_g_object (priv->connection, udi, G_OBJECT (modem));
+ device = mm_modem_get_device (modem);
+ g_assert (device);
+ g_debug ("Removed modem %s", device);
- g_signal_emit (manager, signals[DEVICE_ADDED], 0, modem);
+ g_signal_emit (manager, signals[DEVICE_REMOVED], 0, modem);
+ g_hash_table_remove (priv->modems, device);
+ g_free (device);
}
-static MMModem *
-modem_exists (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);
+ static guint32 id = 0;
+ char *path, *device;
- return (MMModem *) g_hash_table_lookup (priv->modems, udi);
-}
+ 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);
-static void
-create_initial_modems_from_plugins (MMManager *manager)
-{
- MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
- GSList *iter;
+ device = mm_modem_get_device (modem);
+ g_assert (device);
+ g_debug ("Exported modem %s", device);
+ g_free (device);
- for (iter = priv->plugins; iter; iter = iter->next) {
- MMPlugin *plugin = MM_PLUGIN (iter->data);
- char **udis;
- int i;
-
- 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 (modem_exists (manager, udi)) {
- g_warning ("Modem for UDI %s already exists, ignoring", udi);
- continue;
- }
-
- modem = mm_plugin_create_modem (plugin, priv->hal_ctx, udi);
- if (modem)
- add_modem (manager, udi, modem);
- }
-
- g_strfreev (udis);
- }
- }
+ g_signal_emit (manager, signals[DEVICE_ADDED], 0, modem);
+ } else
+ remove_modem (manager, modem);
}
static void
-create_initial_modems_generic (MMManager *manager)
+add_modem (MMManager *manager, MMModem *modem)
{
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);
- }
-
- if (devices) {
- for (i = 0; i < num_devices; i++) {
- char *udi = devices[i];
- MMModem *modem;
-
- if (modem_exists (manager, udi))
- /* Already exists, most likely handled by a plugin */
- continue;
-
- modem = create_generic_modem (manager, udi);
- if (modem)
- add_modem (manager, g_strdup (udi), modem);
- }
+ 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_strfreev (devices);
-}
-
-static void
-create_initial_modems (MMManager *manager)
-{
- create_initial_modems_from_plugins (manager);
- create_initial_modems_generic (manager);
+ g_free (device);
}
static void
enumerate_devices_cb (gpointer key, gpointer val, gpointer user_data)
{
+ MMModem *modem = MM_MODEM (val);
GPtrArray **devices = (GPtrArray **) user_data;
-
- g_ptr_array_add (*devices, g_strdup ((char *) key));
+ 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 gboolean
@@ -325,118 +236,164 @@ impl_manager_enumerate_devices (MMManager *manager,
return TRUE;
}
+typedef struct {
+ MMModem *modem;
+ const char *subsys;
+ const char *name;
+} FindPortInfo;
+
+static void
+find_port (gpointer key, gpointer data, gpointer user_data)
+{
+ FindPortInfo *info = user_data;
+ MMModem *modem = MM_MODEM (data);
+
+ if (!info->modem && mm_modem_owns_port (modem, info->subsys, info->name))
+ info->modem = modem;
+}
+
+static MMModem *
+find_modem_for_port (MMManager *manager, const char *subsys, const char *name)
+{
+ MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
+ FindPortInfo info = { NULL, subsys, name };
+
+ g_hash_table_foreach (priv->modems, find_port, &info);
+ return info.modem;
+}
+
static void
-device_added (LibHalContext *ctx, const char *udi)
+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;
+ MMPlugin *best_plugin = NULL;
+ guint32 best_level = 0;
+ GError *error = NULL;
- if (modem_exists (manager, udi))
- /* Shouldn't happen */
+ g_return_if_fail (device != NULL);
+
+ subsys = g_udev_device_get_subsystem (device);
+ name = g_udev_device_get_name (device);
+
+ if (find_modem_for_port (manager, subsys, name))
return;
- for (iter = priv->plugins; iter && modem == NULL; iter = iter->next) {
+ /* Build up the list of plugins that support this port */
+ for (iter = priv->plugins; iter; iter = iter->next) {
MMPlugin *plugin = MM_PLUGIN (iter->data);
+ guint32 level;
- if (mm_plugin_supports_udi (plugin, ctx, udi)) {
- modem = mm_plugin_create_modem (plugin, ctx, udi);
- if (modem)
- break;
+ level = mm_plugin_supports_port (plugin, subsys, name);
+ if (level > best_level) {
+ best_plugin = plugin;
+ best_level = level;
}
}
- if (!modem)
- /* None of the plugins supported the udi, try generic devices */
- modem = create_generic_modem (manager, udi);
+ /* Let the best plugin handle this port */
+ if (!best_plugin)
+ return;
- if (modem)
- add_modem (manager, udi, modem);
+ modem = mm_plugin_grab_port (best_plugin, subsys, 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 (best_plugin),
+ type_name,
+ mm_modem_get_device (modem),
+ name);
+ } else {
+ g_warning ("%s: plugin '%s' claimed to support %s/%s but couldn't: (%d) %s",
+ __func__, mm_plugin_get_name (best_plugin), subsys, name,
+ error ? error->code : -1,
+ (error && error->message) ? error->message : "(unknown)");
+ return;
+ }
+
+ add_modem (manager, modem);
}
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));
MMModem *modem;
+ const char *subsys, *name;
- modem = modem_exists (manager, udi);
- 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);
- }
+ g_return_if_fail (device != NULL);
+
+ subsys = g_udev_device_get_subsystem (device);
+ name = g_udev_device_get_name (device);
+ modem = find_modem_for_port (manager, subsys, name);
+ if (modem)
+ mm_modem_release_port (modem, subsys, name);
}
static void
-device_new_capability (LibHalContext *ctx, const char *udi, const char *capability)
+handle_uevent (GUdevClient *client,
+ const char *action,
+ GUdevDevice *device,
+ gpointer user_data)
{
- device_added (ctx, udi);
-}
+ MMManager *self = MM_MANAGER (user_data);
+ const char *subsys;
+ g_return_if_fail (action != NULL);
-DBusGConnection *
-mm_manager_get_bus (MMManager *manager)
-{
- g_return_val_if_fail (MM_IS_MANAGER (manager), NULL);
-
- return MM_MANAGER_GET_PRIVATE (manager)->connection;
-}
+ /* A bit paranoid */
+ subsys = g_udev_device_get_subsystem (device);
+ g_return_if_fail (subsys != NULL);
-static gboolean
-remove_one (gpointer key,
- gpointer value,
- gpointer user_data)
-{
- const char *udi = (char *) key;
- MMModem *modem = MM_MODEM (value);
- MMManager *manager = MM_MANAGER (user_data);
+ g_return_if_fail (!strcmp (subsys, "tty") || !strcmp (subsys, "net"));
- g_debug ("Removed modem %s", udi);
- g_signal_emit (manager, signals[DEVICE_REMOVED], 0, modem);
-
- return TRUE;
+ 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->udev = g_udev_client_new (subsys);
+ g_assert (priv->udev);
+ g_signal_connect (priv->udev, "uevent", G_CALLBACK (handle_uevent), manager);
}
static void
@@ -449,11 +406,8 @@ finalize (GObject *object)
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);
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.c b/src/mm-modem.c
index 7bf913ec..be87b79f 100644
--- a/src/mm-modem.c
+++ b/src/mm-modem.c
@@ -199,6 +199,75 @@ impl_modem_disconnect (MMModem *modem,
/*****************************************************************************/
+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,
+ 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, 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;
+}
+
+/*****************************************************************************/
+
static void
mm_modem_init (gpointer g_iface)
{
@@ -210,9 +279,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 +303,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 +327,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..19ec284d 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;
@@ -57,6 +64,19 @@ 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,
+ GError **error);
+
+ void (*release_port) (MMModem *self,
+ const char *subsys,
+ const char *name);
+
void (*enable) (MMModem *self,
gboolean enable,
MMModemFn callback,
@@ -78,6 +98,19 @@ struct _MMModem {
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,
+ 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 +129,9 @@ void mm_modem_disconnect (MMModem *self,
MMModemFn 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.c b/src/mm-plugin.c
index e1fd21c1..c3425538 100644
--- a/src/mm-plugin.c
+++ b/src/mm-plugin.c
@@ -10,49 +10,31 @@ 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)
-{
- g_return_val_if_fail (MM_IS_PLUGIN (plugin), NULL);
- g_return_val_if_fail (hal_ctx != NULL, NULL);
-
- return MM_PLUGIN_GET_INTERFACE (plugin)->list_supported_udis (plugin, hal_ctx);
-}
-
-gboolean
-mm_plugin_supports_udi (MMPlugin *plugin,
- LibHalContext *hal_ctx,
- const char *udi)
+guint32
+mm_plugin_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_val_if_fail (subsys != NULL, FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
- return MM_PLUGIN_GET_INTERFACE (plugin)->supports_udi (plugin, hal_ctx, udi);
+ return MM_PLUGIN_GET_INTERFACE (plugin)->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..07f7f60c 100644
--- a/src/mm-plugin.h
+++ b/src/mm-plugin.h
@@ -4,10 +4,9 @@
#define MM_PLUGIN_H
#include <glib-object.h>
-#include <libhal.h>
#include <mm-modem.h>
-#define MM_PLUGIN_MAJOR_VERSION 1
+#define MM_PLUGIN_MAJOR_VERSION 2
#define MM_PLUGIN_MINOR_VERSION 0
#define MM_TYPE_PLUGIN (mm_plugin_get_type ())
@@ -23,33 +22,44 @@ 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. The plugin should return a
+ * value between 0 and 100 inclusive, where 0 means the plugin has no
+ * support for the device, and 100 means the plugin has full support for the
+ * device.
+ */
+ guint32 (*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);
+guint32 mm_plugin_supports_port (MMPlugin *plugin,
+ const char *subsys,
+ const char *name);
-gboolean mm_plugin_supports_udi (MMPlugin *plugin,
- LibHalContext *hal_ctx,
- const char *udi);
-
-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-serial-port.c b/src/mm-serial-port.c
new file mode 100644
index 00000000..e825d597
--- /dev/null
+++ b/src/mm-serial-port.c
@@ -0,0 +1,1107 @@
+/* -*- 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() */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <termio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <string.h>
+
+#include "mm-serial-port.h"
+#include "mm-errors.h"
+#include "mm-options.h"
+
+static gboolean mm_serial_port_queue_process (gpointer data);
+
+G_DEFINE_TYPE (MMSerialPort, mm_serial_port, G_TYPE_OBJECT)
+
+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_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_SERIAL_PORT, MMSerialPortPrivate))
+
+typedef struct {
+ int fd;
+ GHashTable *reply_cache;
+ GIOChannel *channel;
+ GQueue *queue;
+ GString *command;
+ GString *response;
+
+ /* Response parser data */
+ MMSerialResponseParserFn response_parser_fn;
+ gpointer response_parser_user_data;
+ GDestroyNotify response_parser_notify;
+ GSList *unsolicited_msg_handlers;
+
+ 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;
+} MMSerialPortPrivate;
+
+typedef struct {
+ GRegex *regex;
+ MMSerialUnsolicitedMsgFn callback;
+ gpointer user_data;
+ GDestroyNotify notify;
+} MMUnsolicitedMsgHandler;
+
+const char *
+mm_serial_port_get_device (MMSerialPort *self)
+{
+ g_return_val_if_fail (MM_IS_SERIAL_PORT (self), NULL);
+
+ return MM_SERIAL_PORT_GET_PRIVATE (self)->device;
+}
+
+static void
+mm_serial_port_set_cached_reply (MMSerialPort *self,
+ const char *command,
+ const char *reply)
+{
+ if (reply)
+ 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_PORT_GET_PRIVATE (self)->reply_cache, command);
+}
+
+static const char *
+mm_serial_port_get_cached_reply (MMSerialPort *self,
+ const char *command)
+{
+ return (char *) g_hash_table_lookup (MM_SERIAL_PORT_GET_PRIVATE (self)->reply_cache, command);
+}
+
+static int
+parse_baudrate (guint i)
+{
+ int speed;
+
+ switch (i) {
+ case 0:
+ speed = B0;
+ break;
+ case 50:
+ speed = B50;
+ break;
+ case 75:
+ speed = B75;
+ break;
+ case 110:
+ speed = B110;
+ break;
+ case 150:
+ speed = B150;
+ break;
+ case 300:
+ speed = B300;
+ break;
+ case 600:
+ speed = B600;
+ break;
+ case 1200:
+ speed = B1200;
+ break;
+ case 2400:
+ speed = B2400;
+ break;
+ case 4800:
+ speed = B4800;
+ break;
+ case 9600:
+ speed = B9600;
+ break;
+ case 19200:
+ speed = B19200;
+ break;
+ case 38400:
+ speed = B38400;
+ break;
+ case 57600:
+ speed = B57600;
+ break;
+ case 115200:
+ speed = B115200;
+ break;
+ case 460800:
+ speed = B460800;
+ break;
+ default:
+ g_warning ("Invalid baudrate '%d'", i);
+ speed = B9600;
+ }
+
+ return speed;
+}
+
+static int
+parse_bits (guint i)
+{
+ int bits;
+
+ switch (i) {
+ case 5:
+ bits = CS5;
+ break;
+ case 6:
+ bits = CS6;
+ break;
+ case 7:
+ bits = CS7;
+ break;
+ case 8:
+ bits = CS8;
+ break;
+ default:
+ g_warning ("Invalid bits (%d). Valid values are 5, 6, 7, 8.", i);
+ bits = CS8;
+ }
+
+ return bits;
+}
+
+static int
+parse_parity (char c)
+{
+ int parity;
+
+ switch (c) {
+ case 'n':
+ case 'N':
+ parity = 0;
+ break;
+ case 'e':
+ case 'E':
+ parity = PARENB;
+ break;
+ case 'o':
+ case 'O':
+ parity = PARENB | PARODD;
+ break;
+ default:
+ g_warning ("Invalid parity (%c). Valid values are n, e, o", c);
+ parity = 0;
+ }
+
+ return parity;
+}
+
+static int
+parse_stopbits (guint i)
+{
+ int stopbits;
+
+ switch (i) {
+ case 1:
+ stopbits = 0;
+ break;
+ case 2:
+ stopbits = CSTOPB;
+ break;
+ default:
+ g_warning ("Invalid stop bits (%d). Valid values are 1 and 2)", i);
+ stopbits = 0;
+ }
+
+ return stopbits;
+}
+
+static gboolean
+config_fd (MMSerialPort *self)
+{
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+ struct termio stbuf;
+ int speed;
+ int bits;
+ int parity;
+ int stopbits;
+
+ speed = parse_baudrate (priv->baud);
+ bits = parse_bits (priv->bits);
+ parity = parse_parity (priv->parity);
+ stopbits = parse_stopbits (priv->stopbits);
+
+ ioctl (priv->fd, TCGETA, &stbuf);
+
+ stbuf.c_iflag &= ~(IGNCR | ICRNL | IUCLC | INPCK | IXON | IXANY | IGNPAR );
+ stbuf.c_oflag &= ~(OPOST | OLCUC | OCRNL | ONLCR | ONLRET);
+ stbuf.c_lflag &= ~(ICANON | XCASE | ECHO | ECHOE | ECHONL);
+ stbuf.c_lflag &= ~(ECHO | ECHOE);
+ stbuf.c_cc[VMIN] = 1;
+ stbuf.c_cc[VTIME] = 0;
+ stbuf.c_cc[VEOF] = 1;
+
+ stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | CLOCAL | PARENB);
+ 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);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+serial_debug (const char *prefix, const char *buf, int len)
+{
+ static GString *debug = NULL;
+ const char *s;
+
+ if (!mm_options_debug ())
+ return;
+
+ if (len < 0)
+ len = strlen (buf);
+
+ if (!debug)
+ debug = g_string_sized_new (256);
+
+ g_string_append (debug, prefix);
+ g_string_append (debug, " '");
+
+ s = buf;
+ while (len--) {
+ if (g_ascii_isprint (*s))
+ g_string_append_c (debug, *s);
+ else if (*s == '\r')
+ g_string_append (debug, "<CR>");
+ else if (*s == '\n')
+ g_string_append (debug, "<LF>");
+ else
+ g_string_append_printf (debug, "\\%d", *s);
+
+ s++;
+ }
+
+ g_string_append_c (debug, '\'');
+ g_debug ("%s", debug->str);
+ g_string_truncate (debug, 0);
+}
+
+static gboolean
+mm_serial_port_send_command (MMSerialPort *self,
+ const char *command,
+ GError **error)
+{
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+ const char *s;
+ int status;
+ int eagain_count = 1000;
+
+ 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_port_is_connected (self)) {
+ g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_SEND_FAILED,
+ "%s", "Sending command failed: device is connected");
+ return FALSE;
+ }
+
+ g_string_truncate (priv->command, g_str_has_prefix (command, "AT") ? 0 : 2);
+ g_string_append (priv->command, command);
+
+ if (command[strlen (command)] != '\r')
+ g_string_append_c (priv->command, '\r');
+
+ serial_debug ("-->", priv->command->str, -1);
+
+ s = priv->command->str;
+ while (*s) {
+ status = write (priv->fd, s, 1);
+ if (status < 0) {
+ if (errno == EAGAIN) {
+ eagain_count--;
+ if (eagain_count <= 0) {
+ g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_SEND_FAILED,
+ "Sending command failed: '%s'", strerror (errno));
+ break;
+ }
+ } else {
+ g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_SEND_FAILED,
+ "Sending command failed: '%s'", strerror (errno));
+ break;
+ }
+ } else
+ s++;
+
+ if (priv->send_delay)
+ usleep (priv->send_delay);
+ }
+
+ return *s == '\0';
+}
+
+typedef struct {
+ char *command;
+ MMSerialResponseFn callback;
+ gpointer user_data;
+ guint32 timeout;
+ gboolean cached;
+} MMQueueData;
+
+static void
+mm_serial_port_schedule_queue_process (MMSerialPort *self)
+{
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+ GSource *source;
+
+ if (priv->queue_schedule)
+ /* Already scheduled */
+ return;
+
+ source = g_idle_source_new ();
+ 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_port_got_response (MMSerialPort *self, GError *error)
+{
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+ MMQueueData *info;
+
+ if (priv->timeout_id)
+ g_source_remove (priv->timeout_id);
+
+ info = (MMQueueData *) g_queue_pop_head (priv->queue);
+ if (info) {
+ if (info->cached && !error)
+ mm_serial_port_set_cached_reply (self, info->command, priv->response->str);
+
+ if (info->callback)
+ info->callback (self, priv->response, error, info->user_data);
+
+ g_free (info->command);
+ g_slice_free (MMQueueData, info);
+ }
+
+ if (error)
+ g_error_free (error);
+
+ g_string_truncate (priv->response, 0);
+ if (!g_queue_is_empty (priv->queue))
+ mm_serial_port_schedule_queue_process (self);
+}
+
+static gboolean
+mm_serial_port_timed_out (gpointer data)
+{
+ MMSerialPort *self = MM_SERIAL_PORT (data);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+ GError *error;
+
+ priv->timeout_id = 0;
+
+ error = g_error_new_literal (MM_SERIAL_ERROR,
+ MM_SERIAL_RESPONSE_TIMEOUT,
+ "Serial command timed out");
+ /* 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_port_got_response (self, error);
+
+ return FALSE;
+}
+
+static gboolean
+mm_serial_port_queue_process (gpointer data)
+{
+ MMSerialPort *self = MM_SERIAL_PORT (data);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+ MMQueueData *info;
+ GError *error = NULL;
+
+ priv->queue_schedule = 0;
+
+ info = (MMQueueData *) g_queue_peek_head (priv->queue);
+ if (!info)
+ return FALSE;
+
+ if (info->cached) {
+ const char *cached = mm_serial_port_get_cached_reply (self, info->command);
+
+ if (cached) {
+ g_string_append (priv->response, cached);
+ mm_serial_port_got_response (self, NULL);
+ return FALSE;
+ }
+ }
+
+ 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_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_port_got_response (self, error);
+ }
+
+ return FALSE;
+}
+
+void
+mm_serial_port_add_unsolicited_msg_handler (MMSerialPort *self,
+ GRegex *regex,
+ MMSerialUnsolicitedMsgFn callback,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ MMUnsolicitedMsgHandler *handler;
+ MMSerialPortPrivate *priv;
+
+ g_return_if_fail (MM_IS_SERIAL_PORT (self));
+ g_return_if_fail (regex != NULL);
+
+ handler = g_slice_new (MMUnsolicitedMsgHandler);
+ handler->regex = g_regex_ref (regex);
+ handler->callback = callback;
+ handler->user_data = user_data;
+ handler->notify = notify;
+
+ priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+ priv->unsolicited_msg_handlers = g_slist_append (priv->unsolicited_msg_handlers, handler);
+}
+
+void
+mm_serial_port_set_response_parser (MMSerialPort *self,
+ MMSerialResponseParserFn fn,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+
+ g_return_if_fail (MM_IS_SERIAL_PORT (self));
+
+ if (priv->response_parser_notify)
+ priv->response_parser_notify (priv->response_parser_user_data);
+
+ priv->response_parser_fn = fn;
+ priv->response_parser_user_data = user_data;
+ priv->response_parser_notify = notify;
+}
+
+static gboolean
+remove_eval_cb (const GMatchInfo *match_info,
+ GString *result,
+ gpointer user_data)
+{
+ int *result_len = (int *) user_data;
+ int start;
+ int end;
+
+ if (g_match_info_fetch_pos (match_info, 0, &start, &end))
+ *result_len -= (end - start);
+
+ return FALSE;
+}
+
+static void
+parse_unsolicited_messages (MMSerialPort *self,
+ GString *response)
+{
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+ GSList *iter;
+
+ for (iter = priv->unsolicited_msg_handlers; iter; iter = iter->next) {
+ MMUnsolicitedMsgHandler *handler = (MMUnsolicitedMsgHandler *) iter->data;
+ GMatchInfo *match_info;
+ gboolean matches;
+
+ matches = g_regex_match_full (handler->regex, response->str, response->len, 0, 0, &match_info, NULL);
+ if (handler->callback) {
+ while (g_match_info_matches (match_info)) {
+ handler->callback (self, match_info, handler->user_data);
+ g_match_info_next (match_info, NULL);
+ }
+ }
+
+ g_match_info_free (match_info);
+
+ if (matches) {
+ /* Remove matches */
+ char *str;
+ int result_len = response->len;
+
+ str = g_regex_replace_eval (handler->regex, response->str, response->len, 0, 0,
+ remove_eval_cb, &result_len, NULL);
+
+ g_string_truncate (response, 0);
+ g_string_append_len (response, str, result_len);
+ g_free (str);
+ }
+ }
+}
+
+static gboolean
+parse_response (MMSerialPort *self,
+ GString *response,
+ GError **error)
+{
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+
+ g_return_val_if_fail (priv->response_parser_fn != NULL, FALSE);
+
+ parse_unsolicited_messages (self, response);
+
+ return priv->response_parser_fn (priv->response_parser_user_data, response, error);
+}
+
+static gboolean
+data_available (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ 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_port_close (self);
+ return FALSE;
+ }
+
+ if (condition & G_IO_ERR) {
+ g_string_truncate (priv->response, 0);
+ return TRUE;
+ }
+
+ do {
+ GError *err = NULL;
+
+ status = g_io_channel_read_chars (source, buf, SERIAL_BUF_SIZE, &bytes_read, &err);
+ if (status == G_IO_STATUS_ERROR) {
+ g_warning ("%s", err->message);
+ g_error_free (err);
+ err = NULL;
+ }
+
+ if (bytes_read > 0) {
+ serial_debug ("<--", 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_port_get_device (self));
+ g_string_erase (priv->response, 0, (SERIAL_BUF_SIZE / 2));
+ }
+
+ if (parse_response (self, priv->response, &err))
+ mm_serial_port_got_response (self, err);
+ } while (bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN);
+
+ return TRUE;
+}
+
+gboolean
+mm_serial_port_open (MMSerialPort *self, GError **error)
+{
+ MMSerialPortPrivate *priv;
+ char *devfile;
+
+ g_return_val_if_fail (MM_IS_SERIAL_PORT (self), FALSE);
+
+ priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+
+ if (priv->fd >= 0)
+ /* Already open */
+ return TRUE;
+
+ g_debug ("(%s) opening serial device...", priv->device);
+ devfile = g_strdup_printf ("/dev/%s", priv->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));
+ 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));
+ 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));
+ close (priv->fd);
+ priv->fd = -1;
+ return FALSE;
+ }
+
+ priv->channel = g_io_channel_unix_new (priv->fd);
+ priv->watch_id = g_io_add_watch (priv->channel,
+ G_IO_IN | G_IO_ERR | G_IO_HUP,
+ data_available, self);
+
+ return TRUE;
+}
+
+void
+mm_serial_port_close (MMSerialPort *self)
+{
+ MMSerialPortPrivate *priv;
+
+ g_return_if_fail (MM_IS_SERIAL_PORT (self));
+
+ priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+
+ if (priv->fd >= 0) {
+ g_message ("Closing device '%s'", priv->device);
+
+ if (priv->channel) {
+ g_source_remove (priv->watch_id);
+ g_io_channel_shutdown (priv->channel, TRUE, NULL);
+ g_io_channel_unref (priv->channel);
+ priv->channel = NULL;
+ }
+
+ ioctl (priv->fd, TCSETA, &priv->old_t);
+ close (priv->fd);
+ priv->fd = -1;
+ }
+}
+
+static void
+internal_queue_command (MMSerialPort *self,
+ const char *command,
+ gboolean cached,
+ guint32 timeout_seconds,
+ MMSerialResponseFn callback,
+ gpointer user_data)
+{
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+ MMQueueData *info;
+
+ g_return_if_fail (MM_IS_SERIAL_PORT (self));
+ g_return_if_fail (command != NULL);
+
+ info = g_slice_new0 (MMQueueData);
+ info->command = g_strdup (command);
+ info->cached = cached;
+ info->timeout = timeout_seconds * 1000;
+ info->callback = callback;
+ info->user_data = user_data;
+
+ /* Clear the cached value for this command if not asking for cached value */
+ if (!cached)
+ 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_port_schedule_queue_process (self);
+}
+
+void
+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_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 {
+ MMSerialPort *port;
+ speed_t current_speed;
+ MMSerialFlashFn callback;
+ gpointer user_data;
+} FlashInfo;
+
+static speed_t
+get_speed (MMSerialPort *self)
+{
+ struct termios options;
+
+ tcgetattr (MM_SERIAL_PORT_GET_PRIVATE (self)->fd, &options);
+
+ return cfgetospeed (&options);
+}
+
+static void
+set_speed (MMSerialPort *self, speed_t speed)
+{
+ struct termios options;
+ int fd;
+
+ fd = MM_SERIAL_PORT_GET_PRIVATE (self)->fd;
+ tcgetattr (fd, &options);
+
+ cfsetispeed (&options, speed);
+ cfsetospeed (&options, speed);
+
+ options.c_cflag |= (CLOCAL | CREAD);
+ tcsetattr (fd, TCSANOW, &options);
+}
+
+static void
+flash_done (gpointer data)
+{
+ FlashInfo *info = (FlashInfo *) data;
+
+ info->callback (info->port, info->user_data);
+
+ g_slice_free (FlashInfo, info);
+}
+
+static gboolean
+flash_do (gpointer data)
+{
+ FlashInfo *info = (FlashInfo *) data;
+
+ set_speed (info->port, info->current_speed);
+
+ return FALSE;
+}
+
+guint
+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_PORT (self), 0);
+ g_return_val_if_fail (callback != NULL, 0);
+
+ info = g_slice_new0 (FlashInfo);
+ info->port = self;
+ info->current_speed = get_speed (self);
+ info->callback = callback;
+ info->user_data = user_data;
+
+ set_speed (self, B0);
+
+ id = g_timeout_add_full (G_PRIORITY_DEFAULT,
+ flash_time,
+ flash_do,
+ info,
+ flash_done);
+
+ return id;
+}
+
+gboolean
+mm_serial_port_is_connected (MMSerialPort *self)
+{
+ MMSerialPortPrivate *priv;
+ int mcs = 0;
+
+ g_return_val_if_fail (MM_IS_SERIAL_PORT (self), FALSE);
+
+ priv = MM_SERIAL_PORT_GET_PRIVATE (self);
+
+ if (!priv->carrier_detect)
+ return FALSE;
+
+ if (priv->fd < 0)
+ return FALSE;
+
+ if (ioctl (priv->fd, TIOCMGET, &mcs) < 0)
+ return FALSE;
+
+ return mcs & TIOCM_CAR ? TRUE : FALSE;
+}
+
+/*****************************************************************************/
+
+MMSerialPort *
+mm_serial_port_new (const char *name)
+{
+ return MM_SERIAL_PORT (g_object_new (MM_TYPE_SERIAL_PORT,
+ MM_SERIAL_PORT_DEVICE, name,
+ NULL));
+}
+
+static void
+mm_serial_port_init (MMSerialPort *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;
+ MMSerialPortPrivate *priv;
+
+ object = G_OBJECT_CLASS (mm_serial_port_parent_class)->constructor (type,
+ n_construct_params,
+ construct_params);
+ if (!object)
+ return NULL;
+
+ priv = MM_SERIAL_PORT_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)
+{
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (object);
+
+ switch (prop_id) {
+ case PROP_DEVICE:
+ /* Construct only */
+ priv->device = g_path_get_basename (g_value_get_string (value));
+ break;
+ case PROP_BAUD:
+ priv->baud = g_value_get_uint (value);
+ break;
+ case PROP_BITS:
+ priv->bits = g_value_get_uint (value);
+ break;
+ case PROP_PARITY:
+ priv->parity = g_value_get_char (value);
+ break;
+ case PROP_STOPBITS:
+ priv->stopbits = g_value_get_uint (value);
+ break;
+ 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;
+ }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ 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;
+ case PROP_BITS:
+ g_value_set_uint (value, priv->bits);
+ break;
+ case PROP_PARITY:
+ g_value_set_char (value, priv->parity);
+ break;
+ case PROP_STOPBITS:
+ g_value_set_uint (value, priv->stopbits);
+ break;
+ 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;
+ }
+}
+
+static void
+finalize (GObject *object)
+{
+ MMSerialPort *self = MM_SERIAL_PORT (object);
+ MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (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;
+
+ if (handler->notify)
+ handler->notify (handler->user_data);
+
+ g_regex_unref (handler->regex);
+ g_slice_free (MMUnsolicitedMsgHandler, handler);
+ priv->unsolicited_msg_handlers = g_slist_delete_link (priv->unsolicited_msg_handlers,
+ priv->unsolicited_msg_handlers);
+ }
+
+ if (priv->response_parser_notify)
+ priv->response_parser_notify (priv->response_parser_user_data);
+
+ G_OBJECT_CLASS (mm_serial_port_parent_class)->finalize (object);
+}
+
+static void
+mm_serial_port_class_init (MMSerialPortClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ 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_PORT_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_PORT_BAUD,
+ "Baud",
+ "Baud rate",
+ 0, G_MAXUINT, 57600,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property
+ (object_class, PROP_BITS,
+ g_param_spec_uint (MM_SERIAL_PORT_BITS,
+ "Bits",
+ "Bits",
+ 5, 8, 8,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property
+ (object_class, PROP_PARITY,
+ g_param_spec_char (MM_SERIAL_PORT_PARITY,
+ "Parity",
+ "Parity",
+ 'E', 'o', 'n',
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property
+ (object_class, PROP_STOPBITS,
+ g_param_spec_uint (MM_SERIAL_PORT_STOPBITS,
+ "Stopbits",
+ "Stopbits",
+ 1, 2, 1,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property
+ (object_class, PROP_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_PORT_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..7056527a
--- /dev/null
+++ b/src/mm-serial-port.h
@@ -0,0 +1,114 @@
+/* -*- 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>
+
+typedef enum {
+ MM_SERIAL_PORT_TYPE_UNKNOWN = 0x0,
+ MM_SERIAL_PORT_TYPE_PRIMARY,
+ MM_SERIAL_PORT_TYPE_SECONDARY,
+ MM_SERIAL_PORT_TYPE_IGNORED
+} MMSerialPortType;
+
+#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_DEVICE "serial-device"
+#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"
+#define MM_SERIAL_PORT_CARRIER_DETECT "carrier-detect"
+
+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 {
+ GObject parent;
+};
+
+struct _MMSerialPortClass {
+ GObjectClass parent;
+};
+
+GType mm_serial_port_get_type (void);
+
+MMSerialPort *mm_serial_port_new (const char *name);
+
+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);
+
+const char *mm_serial_port_get_device (MMSerialPort *self);
+
+#endif /* MM_SERIAL_PORT_H */
+
diff --git a/src/mm-serial.c b/src/mm-serial.c
index 0301a592..48492ce4 100644
--- a/src/mm-serial.c
+++ b/src/mm-serial.c
@@ -1,864 +1,100 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-
-#define _GNU_SOURCE /* for strcasestr() */
+/*
+ * 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 <termio.h>
#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/ioctl.h>
#include <string.h>
#include "mm-serial.h"
#include "mm-errors.h"
#include "mm-options.h"
-static gboolean mm_serial_queue_process (gpointer data);
+#define TYPE_TAG "type"
G_DEFINE_TYPE (MMSerial, mm_serial, G_TYPE_OBJECT)
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))
typedef struct {
- int fd;
- GHashTable *reply_cache;
- GIOChannel *channel;
- GQueue *queue;
- GString *command;
- GString *response;
-
- /* Response parser data */
- MMSerialResponseParserFn response_parser_fn;
- gpointer response_parser_user_data;
- GDestroyNotify response_parser_notify;
- GSList *unsolicited_msg_handlers;
-
- 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;
+ GHashTable *ports;
} MMSerialPrivate;
-typedef struct {
- GRegex *regex;
- MMSerialUnsolicitedMsgFn callback;
- gpointer user_data;
- 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)
-{
- if (reply)
- g_hash_table_insert (MM_SERIAL_GET_PRIVATE (self)->reply_cache,
- g_strdup (command),
- g_strdup (reply));
- else
- g_hash_table_remove (MM_SERIAL_GET_PRIVATE (self)->reply_cache, command);
-}
-
-static const char *
-mm_serial_get_cached_reply (MMSerial *self,
- const char *command)
-{
- return (char *) g_hash_table_lookup (MM_SERIAL_GET_PRIVATE (self)->reply_cache, command);
-}
-
-static int
-parse_baudrate (guint i)
-{
- int speed;
-
- switch (i) {
- case 0:
- speed = B0;
- break;
- case 50:
- speed = B50;
- break;
- case 75:
- speed = B75;
- break;
- case 110:
- speed = B110;
- break;
- case 150:
- speed = B150;
- break;
- case 300:
- speed = B300;
- break;
- case 600:
- speed = B600;
- break;
- case 1200:
- speed = B1200;
- break;
- case 2400:
- speed = B2400;
- break;
- case 4800:
- speed = B4800;
- break;
- case 9600:
- speed = B9600;
- break;
- case 19200:
- speed = B19200;
- break;
- case 38400:
- speed = B38400;
- break;
- case 57600:
- speed = B57600;
- break;
- case 115200:
- speed = B115200;
- break;
- case 460800:
- speed = B460800;
- break;
- default:
- g_warning ("Invalid baudrate '%d'", i);
- speed = B9600;
- }
-
- return speed;
-}
-
-static int
-parse_bits (guint i)
-{
- int bits;
-
- switch (i) {
- case 5:
- bits = CS5;
- break;
- case 6:
- bits = CS6;
- break;
- case 7:
- bits = CS7;
- break;
- case 8:
- bits = CS8;
- break;
- default:
- g_warning ("Invalid bits (%d). Valid values are 5, 6, 7, 8.", i);
- bits = CS8;
- }
-
- return bits;
-}
-
-static int
-parse_parity (char c)
-{
- int parity;
-
- switch (c) {
- case 'n':
- case 'N':
- parity = 0;
- break;
- case 'e':
- case 'E':
- parity = PARENB;
- break;
- case 'o':
- case 'O':
- parity = PARENB | PARODD;
- break;
- default:
- g_warning ("Invalid parity (%c). Valid values are n, e, o", c);
- parity = 0;
- }
-
- return parity;
-}
-
-static int
-parse_stopbits (guint i)
-{
- int stopbits;
-
- switch (i) {
- case 1:
- stopbits = 0;
- break;
- case 2:
- stopbits = CSTOPB;
- break;
- default:
- g_warning ("Invalid stop bits (%d). Valid values are 1 and 2)", i);
- stopbits = 0;
- }
-
- return stopbits;
-}
-
-static gboolean
-config_fd (MMSerial *self)
-{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- struct termio stbuf;
- int speed;
- int bits;
- int parity;
- int stopbits;
-
- speed = parse_baudrate (priv->baud);
- bits = parse_bits (priv->bits);
- parity = parse_parity (priv->parity);
- stopbits = parse_stopbits (priv->stopbits);
-
- ioctl (priv->fd, TCGETA, &stbuf);
-
- stbuf.c_iflag &= ~(IGNCR | ICRNL | IUCLC | INPCK | IXON | IXANY | IGNPAR );
- stbuf.c_oflag &= ~(OPOST | OLCUC | OCRNL | ONLCR | ONLRET);
- stbuf.c_lflag &= ~(ICANON | XCASE | ECHO | ECHOE | ECHONL);
- stbuf.c_lflag &= ~(ECHO | ECHOE);
- stbuf.c_cc[VMIN] = 1;
- stbuf.c_cc[VTIME] = 0;
- stbuf.c_cc[VEOF] = 1;
-
- stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | CLOCAL | PARENB);
- 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);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void
-serial_debug (const char *prefix, const char *buf, int len)
-{
- static GString *debug = NULL;
- const char *s;
-
- if (!mm_options_debug ())
- return;
-
- if (len < 0)
- len = strlen (buf);
-
- if (!debug)
- debug = g_string_sized_new (256);
-
- g_string_append (debug, prefix);
- g_string_append (debug, " '");
-
- s = buf;
- while (len--) {
- if (g_ascii_isprint (*s))
- g_string_append_c (debug, *s);
- else if (*s == '\r')
- g_string_append (debug, "<CR>");
- else if (*s == '\n')
- g_string_append (debug, "<LF>");
- else
- g_string_append_printf (debug, "\\%d", *s);
-
- s++;
- }
-
- g_string_append_c (debug, '\'');
- g_debug ("%s", debug->str);
- g_string_truncate (debug, 0);
-}
-
-static gboolean
-mm_serial_send_command (MMSerial *self,
- const char *command,
- GError **error)
+MMSerialPort *
+mm_serial_get_port (MMSerial *self, const char *name)
{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- const char *s;
- int status;
- int eagain_count = 1000;
-
- 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)) {
- g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_SEND_FAILED,
- "%s", "Sending command failed: device is connected");
- return FALSE;
- }
-
- g_string_truncate (priv->command, g_str_has_prefix (command, "AT") ? 0 : 2);
- g_string_append (priv->command, command);
-
- if (command[strlen (command)] != '\r')
- g_string_append_c (priv->command, '\r');
-
- serial_debug ("-->", priv->command->str, -1);
-
- s = priv->command->str;
- while (*s) {
- status = write (priv->fd, s, 1);
- if (status < 0) {
- if (errno == EAGAIN) {
- eagain_count--;
- if (eagain_count <= 0) {
- g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_SEND_FAILED,
- "Sending command failed: '%s'", strerror (errno));
- break;
- }
- } else {
- g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_SEND_FAILED,
- "Sending command failed: '%s'", strerror (errno));
- break;
- }
- } else
- s++;
-
- if (priv->send_delay)
- usleep (priv->send_delay);
- }
-
- return *s == '\0';
+ return g_hash_table_lookup (MM_SERIAL_GET_PRIVATE (self)->ports, name);
}
-typedef struct {
- char *command;
- MMSerialResponseFn callback;
- gpointer user_data;
- guint32 timeout;
- gboolean cached;
-} MMQueueData;
-
static void
-mm_serial_schedule_queue_process (MMSerial *self)
+find_primary (gpointer key, gpointer data, gpointer user_data)
{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- GSource *source;
+ MMSerialPort **found = user_data;
+ MMSerialPort *port = MM_SERIAL_PORT (data);
+ MMSerialPortType ptype;
- if (priv->queue_schedule)
- /* Already scheduled */
+ if (*found)
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_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)
-{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- MMQueueData *info;
-
- if (priv->timeout_id)
- g_source_remove (priv->timeout_id);
-
- 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);
-
- if (info->callback)
- info->callback (self, priv->response, error, info->user_data);
-
- g_free (info->command);
- g_slice_free (MMQueueData, info);
- }
-
- if (error)
- g_error_free (error);
-
- g_string_truncate (priv->response, 0);
- if (!g_queue_is_empty (priv->queue))
- mm_serial_schedule_queue_process (self);
-}
-
-static gboolean
-mm_serial_timed_out (gpointer data)
-{
- MMSerial *self = MM_SERIAL (data);
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- GError *error;
-
- priv->timeout_id = 0;
-
- error = g_error_new_literal (MM_SERIAL_ERROR,
- MM_SERIAL_RESPONSE_TIMEOUT,
- "Serial command timed out");
- /* 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);
-
- return FALSE;
-}
-
-static gboolean
-mm_serial_queue_process (gpointer data)
-{
- MMSerial *self = MM_SERIAL (data);
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- MMQueueData *info;
- GError *error = NULL;
-
- priv->queue_schedule = 0;
-
- info = (MMQueueData *) g_queue_peek_head (priv->queue);
- if (!info)
- return FALSE;
-
- if (info->cached) {
- const char *cached = mm_serial_get_cached_reply (self, info->command);
-
- if (cached) {
- g_string_append (priv->response, cached);
- mm_serial_got_response (self, NULL);
- return FALSE;
- }
- }
-
- if (mm_serial_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_attach (source, NULL);
- priv->timeout_id = g_source_get_id (source);
- g_source_unref (source);
- } else {
- mm_serial_got_response (self, error);
- }
-
- return FALSE;
-}
-
-void
-mm_serial_add_unsolicited_msg_handler (MMSerial *self,
- GRegex *regex,
- MMSerialUnsolicitedMsgFn callback,
- gpointer user_data,
- GDestroyNotify notify)
-{
- MMUnsolicitedMsgHandler *handler;
- MMSerialPrivate *priv;
-
- g_return_if_fail (MM_IS_SERIAL (self));
- g_return_if_fail (regex != NULL);
-
- handler = g_slice_new (MMUnsolicitedMsgHandler);
- handler->regex = g_regex_ref (regex);
- handler->callback = callback;
- handler->user_data = user_data;
- handler->notify = notify;
-
- priv = MM_SERIAL_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)
-{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
-
- g_return_if_fail (MM_IS_SERIAL (self));
-
- if (priv->response_parser_notify)
- priv->response_parser_notify (priv->response_parser_user_data);
-
- priv->response_parser_fn = fn;
- priv->response_parser_user_data = user_data;
- priv->response_parser_notify = notify;
-}
-
-static gboolean
-remove_eval_cb (const GMatchInfo *match_info,
- GString *result,
- gpointer user_data)
-{
- int *result_len = (int *) user_data;
- int start;
- int end;
-
- if (g_match_info_fetch_pos (match_info, 0, &start, &end))
- *result_len -= (end - start);
-
- return FALSE;
-}
-
-static void
-parse_unsolicited_messages (MMSerial *self,
- GString *response)
-{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- GSList *iter;
-
- for (iter = priv->unsolicited_msg_handlers; iter; iter = iter->next) {
- MMUnsolicitedMsgHandler *handler = (MMUnsolicitedMsgHandler *) iter->data;
- GMatchInfo *match_info;
- gboolean matches;
-
- matches = g_regex_match_full (handler->regex, response->str, response->len, 0, 0, &match_info, NULL);
- if (handler->callback) {
- while (g_match_info_matches (match_info)) {
- handler->callback (self, match_info, handler->user_data);
- g_match_info_next (match_info, NULL);
- }
- }
-
- g_match_info_free (match_info);
-
- if (matches) {
- /* Remove matches */
- char *str;
- int result_len = response->len;
-
- str = g_regex_replace_eval (handler->regex, response->str, response->len, 0, 0,
- remove_eval_cb, &result_len, NULL);
-
- g_string_truncate (response, 0);
- g_string_append_len (response, str, result_len);
- g_free (str);
- }
- }
-}
-
-static gboolean
-parse_response (MMSerial *self,
- GString *response,
- GError **error)
-{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
-
- g_return_val_if_fail (priv->response_parser_fn != NULL, FALSE);
-
- parse_unsolicited_messages (self, response);
-
- return priv->response_parser_fn (priv->response_parser_user_data, response, error);
+ ptype = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (port), TYPE_TAG));
+ if (ptype == MM_SERIAL_PORT_TYPE_PRIMARY)
+ *found = port;
}
-static gboolean
-data_available (GIOChannel *source,
- GIOCondition condition,
- gpointer data)
+MMSerialPort *
+mm_serial_add_port (MMSerial *self,
+ const char *name,
+ MMSerialPortType ptype)
{
- MMSerial *self = MM_SERIAL (data);
MMSerialPrivate *priv = MM_SERIAL_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);
- return FALSE;
- }
-
- if (condition & G_IO_ERR) {
- g_string_truncate (priv->response, 0);
- return TRUE;
- }
-
- do {
- GError *err = NULL;
-
- status = g_io_channel_read_chars (source, buf, SERIAL_BUF_SIZE, &bytes_read, &err);
- if (status == G_IO_STATUS_ERROR) {
- g_warning ("%s", err->message);
- g_error_free (err);
- err = NULL;
- }
-
- if (bytes_read > 0) {
- serial_debug ("<--", 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_string_erase (priv->response, 0, (SERIAL_BUF_SIZE / 2));
- }
-
- if (parse_response (self, priv->response, &err))
- mm_serial_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)
-{
- MMSerialPrivate *priv;
+ MMSerialPort *port = NULL;
g_return_val_if_fail (MM_IS_SERIAL (self), FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+ g_return_val_if_fail (ptype != MM_SERIAL_PORT_TYPE_UNKNOWN, FALSE);
- priv = MM_SERIAL_GET_PRIVATE (self);
-
- if (priv->fd)
- /* 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);
-
- 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));
- 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));
- close (priv->fd);
- 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));
- close (priv->fd);
- priv->fd = 0;
- return FALSE;
- }
-
- priv->channel = g_io_channel_unix_new (priv->fd);
- priv->watch_id = g_io_add_watch (priv->channel,
- G_IO_IN | G_IO_ERR | G_IO_HUP,
- data_available, self);
-
- return TRUE;
-}
-
-void
-mm_serial_close (MMSerial *self)
-{
- MMSerialPrivate *priv;
-
- g_return_if_fail (MM_IS_SERIAL (self));
-
- priv = MM_SERIAL_GET_PRIVATE (self);
-
- if (priv->fd) {
- g_message ("Closing device '%s'", priv->device);
+ g_return_val_if_fail (g_hash_table_lookup (priv->ports, name) == NULL, FALSE);
- if (priv->channel) {
- g_source_remove (priv->watch_id);
- g_io_channel_shutdown (priv->channel, TRUE, NULL);
- g_io_channel_unref (priv->channel);
- priv->channel = NULL;
- }
-
- ioctl (priv->fd, TCSETA, &priv->old_t);
- close (priv->fd);
- priv->fd = 0;
+ if (ptype == MM_SERIAL_PORT_TYPE_PRIMARY) {
+ g_hash_table_foreach (priv->ports, find_primary, &port);
+ g_return_val_if_fail (port == NULL, FALSE);
}
-}
-
-static void
-internal_queue_command (MMSerial *self,
- const char *command,
- gboolean cached,
- guint32 timeout_seconds,
- MMSerialResponseFn callback,
- gpointer user_data)
-{
- MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- MMQueueData *info;
-
- g_return_if_fail (MM_IS_SERIAL (self));
- g_return_if_fail (command != NULL);
-
- info = g_slice_new0 (MMQueueData);
- info->command = g_strdup (command);
- info->cached = cached;
- info->timeout = timeout_seconds * 1000;
- info->callback = callback;
- info->user_data = user_data;
-
- /* Clear the cached value for this command if not asking for cached value */
- if (!cached)
- mm_serial_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);
-}
-
-void
-mm_serial_queue_command (MMSerial *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)
-{
- internal_queue_command (self, command, TRUE, timeout_seconds, callback, user_data);
-}
-
-typedef struct {
- MMSerial *serial;
- speed_t current_speed;
- MMSerialFlashFn callback;
- gpointer user_data;
-} FlashInfo;
-
-static speed_t
-get_speed (MMSerial *self)
-{
- struct termios options;
-
- tcgetattr (MM_SERIAL_GET_PRIVATE (self)->fd, &options);
-
- return cfgetospeed (&options);
-}
-
-static void
-set_speed (MMSerial *self, speed_t speed)
-{
- struct termios options;
- int fd;
-
- fd = MM_SERIAL_GET_PRIVATE (self)->fd;
- tcgetattr (fd, &options);
-
- cfsetispeed (&options, speed);
- cfsetospeed (&options, speed);
-
- options.c_cflag |= (CLOCAL | CREAD);
- tcsetattr (fd, TCSANOW, &options);
-}
-
-static void
-flash_done (gpointer data)
-{
- FlashInfo *info = (FlashInfo *) data;
-
- info->callback (info->serial, info->user_data);
-
- g_slice_free (FlashInfo, info);
-}
-static gboolean
-flash_do (gpointer data)
-{
- FlashInfo *info = (FlashInfo *) data;
-
- set_speed (info->serial, info->current_speed);
-
- return FALSE;
-}
-
-guint
-mm_serial_flash (MMSerial *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 (callback != NULL, 0);
-
- info = g_slice_new0 (FlashInfo);
- info->serial = self;
- info->current_speed = get_speed (self);
- info->callback = callback;
- info->user_data = user_data;
-
- set_speed (self, B0);
-
- id = g_timeout_add_full (G_PRIORITY_DEFAULT,
- flash_time,
- flash_do,
- info,
- flash_done);
+ port = mm_serial_port_new (name);
+ if (!port)
+ return NULL;
- return id;
+ g_object_set_data (G_OBJECT (port), TYPE_TAG, GUINT_TO_POINTER (ptype));
+ g_hash_table_insert (priv->ports, g_strdup (name), port);
+ return port;
}
gboolean
-mm_serial_is_connected (MMSerial *self)
+mm_serial_remove_port (MMSerial *self, MMSerialPort *port)
{
- MMSerialPrivate *priv;
- int mcs = 0;
-
g_return_val_if_fail (MM_IS_SERIAL (self), FALSE);
+ g_return_val_if_fail (port != NULL, FALSE);
- priv = MM_SERIAL_GET_PRIVATE (self);
-
- if (!priv->carrier_detect)
- return FALSE;
-
- if (priv->fd == 0)
- return FALSE;
-
- if (ioctl (priv->fd, TIOCMGET, &mcs) < 0)
- return FALSE;
-
- return mcs & TIOCM_CAR ? TRUE : FALSE;
+ return g_hash_table_remove (MM_SERIAL_GET_PRIVATE (self)->ports, port);
}
/*****************************************************************************/
@@ -868,74 +104,14 @@ mm_serial_init (MMSerial *self)
{
MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- priv->reply_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-
- 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;
+ priv->ports = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
}
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
- MMSerialPrivate *priv = MM_SERIAL_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;
- case PROP_BITS:
- priv->bits = g_value_get_uint (value);
- break;
- case PROP_PARITY:
- priv->parity = g_value_get_char (value);
- break;
- case PROP_STOPBITS:
- priv->stopbits = g_value_get_uint (value);
- break;
- 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,30 +122,7 @@ static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
- MMSerialPrivate *priv = MM_SERIAL_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;
- case PROP_BITS:
- g_value_set_uint (value, priv->bits);
- break;
- case PROP_PARITY:
- g_value_set_char (value, priv->parity);
- break;
- case PROP_STOPBITS:
- g_value_set_uint (value, priv->stopbits);
- break;
- 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;
@@ -982,28 +135,7 @@ finalize (GObject *object)
MMSerial *self = MM_SERIAL (object);
MMSerialPrivate *priv = MM_SERIAL_GET_PRIVATE (self);
- mm_serial_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;
-
- if (handler->notify)
- handler->notify (handler->user_data);
-
- g_regex_unref (handler->regex);
- g_slice_free (MMUnsolicitedMsgHandler, handler);
- priv->unsolicited_msg_handlers = g_slist_delete_link (priv->unsolicited_msg_handlers,
- priv->unsolicited_msg_handlers);
- }
-
- if (priv->response_parser_notify)
- priv->response_parser_notify (priv->response_parser_user_data);
+ g_hash_table_destroy (priv->ports);
G_OBJECT_CLASS (mm_serial_parent_class)->finalize (object);
}
@@ -1016,65 +148,7 @@ mm_serial_class_init (MMSerialClass *klass)
g_type_class_add_private (object_class, sizeof (MMSerialPrivate));
/* 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,
- "Baud",
- "Baud rate",
- 0, G_MAXUINT, 57600,
- G_PARAM_READWRITE));
-
- g_object_class_install_property
- (object_class, PROP_BITS,
- g_param_spec_uint (MM_SERIAL_BITS,
- "Bits",
- "Bits",
- 5, 8, 8,
- G_PARAM_READWRITE));
-
- g_object_class_install_property
- (object_class, PROP_PARITY,
- g_param_spec_char (MM_SERIAL_PARITY,
- "Parity",
- "Parity",
- 'E', 'o', 'n',
- G_PARAM_READWRITE));
-
- g_object_class_install_property
- (object_class, PROP_STOPBITS,
- g_param_spec_uint (MM_SERIAL_STOPBITS,
- "Stopbits",
- "Stopbits",
- 1, 2, 1,
- G_PARAM_READWRITE));
-
- g_object_class_install_property
- (object_class, PROP_SEND_DELAY,
- g_param_spec_uint64 (MM_SERIAL_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.h b/src/mm-serial.h
index e3479eed..b6c2b5ec 100644
--- a/src/mm-serial.h
+++ b/src/mm-serial.h
@@ -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.
+ */
#ifndef MM_SERIAL_H
#define MM_SERIAL_H
@@ -7,6 +21,8 @@
#include <glib/gtypes.h>
#include <glib-object.h>
+#include "mm-serial-port.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))
@@ -14,33 +30,9 @@
#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;
};
@@ -51,39 +43,15 @@ struct _MMSerialClass {
GType mm_serial_get_type (void);
-void mm_serial_add_unsolicited_msg_handler (MMSerial *self,
- GRegex *regex,
- MMSerialUnsolicitedMsgFn callback,
- gpointer user_data,
- GDestroyNotify notify);
+MMSerialPort *mm_serial_get_port (MMSerial *self,
+ const char *name);
-void mm_serial_set_response_parser (MMSerial *self,
- MMSerialResponseParserFn fn,
- gpointer user_data,
- GDestroyNotify notify);
+MMSerialPort *mm_serial_add_port (MMSerial *self,
+ const char *name,
+ MMSerialPortType ptype);
-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);
+gboolean mm_serial_remove_port (MMSerial *self,
+ MMSerialPort *port);
#endif /* MM_SERIAL_H */
+