diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 10 | ||||
-rw-r--r-- | src/mm-at-serial-port.c | 323 | ||||
-rw-r--r-- | src/mm-at-serial-port.h | 85 | ||||
-rw-r--r-- | src/mm-generic-cdma.c | 94 | ||||
-rw-r--r-- | src/mm-generic-cdma.h | 4 | ||||
-rw-r--r-- | src/mm-generic-gsm.c | 182 | ||||
-rw-r--r-- | src/mm-generic-gsm.h | 6 | ||||
-rw-r--r-- | src/mm-manager.c | 12 | ||||
-rw-r--r-- | src/mm-modem-base.c | 4 | ||||
-rw-r--r-- | src/mm-plugin-base.c | 54 | ||||
-rw-r--r-- | src/mm-qcdm-serial-port.c | 176 | ||||
-rw-r--r-- | src/mm-qcdm-serial-port.h | 66 | ||||
-rw-r--r-- | src/mm-serial-port.c | 344 | ||||
-rw-r--r-- | src/mm-serial-port.h | 78 |
14 files changed, 1030 insertions, 408 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index a695f374..3d938063 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,7 @@ sbin_PROGRAMS = modem-manager modem_manager_CPPFLAGS = \ $(MM_CFLAGS) \ $(GUDEV_CFLAGS) \ + $(top_srcdir) \ -I${top_builddir}/marshallers \ -DPLUGINDIR=\"$(pkglibdir)\" @@ -27,6 +28,7 @@ modem_manager_LDADD = \ $(MM_LIBS) \ $(GUDEV_LIBS) \ $(top_builddir)/marshallers/libmarshallers.la \ + $(top_builddir)/libqcdm/src/libqcdm.la \ $(builddir)/libmodem-helpers.la if WITH_POLKIT @@ -59,12 +61,16 @@ modem_manager_SOURCES = \ mm-modem.h \ mm-port.c \ mm-port.h \ - mm-modem-base.c \ - mm-modem-base.h \ mm-serial-port.c \ mm-serial-port.h \ + mm-at-serial-port.c \ + mm-at-serial-port.h \ + mm-qcdm-serial-port.c \ + mm-qcdm-serial-port.h \ mm-serial-parsers.c \ mm-serial-parsers.h \ + mm-modem-base.c \ + mm-modem-base.h \ mm-generic-cdma.c \ mm-generic-cdma.h \ mm-generic-gsm.c \ diff --git a/src/mm-at-serial-port.c b/src/mm-at-serial-port.c new file mode 100644 index 00000000..fd4ff6e4 --- /dev/null +++ b/src/mm-at-serial-port.c @@ -0,0 +1,323 @@ +/* -*- 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 <unistd.h> +#include <string.h> + +#include "mm-at-serial-port.h" +#include "mm-errors.h" +#include "mm-options.h" + +G_DEFINE_TYPE (MMAtSerialPort, mm_at_serial_port, MM_TYPE_SERIAL_PORT) + +#define MM_AT_SERIAL_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_AT_SERIAL_PORT, MMAtSerialPortPrivate)) + +typedef struct { + /* Response parser data */ + MMAtSerialResponseParserFn response_parser_fn; + gpointer response_parser_user_data; + GDestroyNotify response_parser_notify; + GSList *unsolicited_msg_handlers; +} MMAtSerialPortPrivate; + + +/*****************************************************************************/ + +void +mm_at_serial_port_set_response_parser (MMAtSerialPort *self, + MMAtSerialResponseParserFn fn, + gpointer user_data, + GDestroyNotify notify) +{ + MMAtSerialPortPrivate *priv = MM_AT_SERIAL_PORT_GET_PRIVATE (self); + + g_return_if_fail (MM_IS_AT_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 +parse_response (MMSerialPort *port, GByteArray *response, GError **error) +{ + MMAtSerialPort *self = MM_AT_SERIAL_PORT (port); + MMAtSerialPortPrivate *priv = MM_AT_SERIAL_PORT_GET_PRIVATE (self); + gboolean found; + GString *string; + + g_return_val_if_fail (priv->response_parser_fn != NULL, FALSE); + + /* Construct the string that AT-parsing functions expect */ + string = g_string_sized_new (response->len + 1); + g_string_append_len (string, (const char *) response->data, response->len); + + /* Parse it */ + found = priv->response_parser_fn (priv->response_parser_user_data, string, error); + + /* And copy it back into the response array after the parser has removed + * matches and cleaned it up. + */ + g_byte_array_remove_range (response, 0, response->len); + g_byte_array_append (response, (const guint8 *) string->str, string->len); + g_string_free (string, TRUE); + return found; +} + +static void +handle_response (MMSerialPort *port, + GByteArray *response, + GError *error, + GCallback callback, + gpointer callback_data) +{ + MMAtSerialPort *self = MM_AT_SERIAL_PORT (port); + MMAtSerialResponseFn response_callback = (MMAtSerialResponseFn) callback; + GString *string; + + /* Convert to a string and call the callback */ + string = g_string_sized_new (response->len + 1); + g_string_append_len (string, (const char *) response->data, response->len); + response_callback (self, string, error, callback_data); + g_string_free (string, TRUE); +} + +/*****************************************************************************/ + +typedef struct { + GRegex *regex; + MMAtSerialUnsolicitedMsgFn callback; + gpointer user_data; + GDestroyNotify notify; +} MMAtUnsolicitedMsgHandler; + +void +mm_at_serial_port_add_unsolicited_msg_handler (MMAtSerialPort *self, + GRegex *regex, + MMAtSerialUnsolicitedMsgFn callback, + gpointer user_data, + GDestroyNotify notify) +{ + MMAtUnsolicitedMsgHandler *handler; + MMAtSerialPortPrivate *priv; + + g_return_if_fail (MM_IS_AT_SERIAL_PORT (self)); + g_return_if_fail (regex != NULL); + + handler = g_slice_new (MMAtUnsolicitedMsgHandler); + handler->regex = g_regex_ref (regex); + handler->callback = callback; + handler->user_data = user_data; + handler->notify = notify; + + priv = MM_AT_SERIAL_PORT_GET_PRIVATE (self); + priv->unsolicited_msg_handlers = g_slist_append (priv->unsolicited_msg_handlers, handler); +} + +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 (MMSerialPort *port, GByteArray *response) +{ + MMAtSerialPort *self = MM_AT_SERIAL_PORT (port); + MMAtSerialPortPrivate *priv = MM_AT_SERIAL_PORT_GET_PRIVATE (self); + GSList *iter; + + for (iter = priv->unsolicited_msg_handlers; iter; iter = iter->next) { + MMAtUnsolicitedMsgHandler *handler = (MMAtUnsolicitedMsgHandler *) iter->data; + GMatchInfo *match_info; + gboolean matches; + + matches = g_regex_match_full (handler->regex, + (const char *) response->data, + 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, + (const char *) response->data, + response->len, + 0, 0, + remove_eval_cb, &result_len, NULL); + + g_byte_array_remove_range (response, 0, response->len); + g_byte_array_append (response, (const guint8 *) str, result_len); + g_free (str); + } + } +} + +/*****************************************************************************/ + +static GByteArray * +at_command_to_byte_array (const char *command) +{ + GByteArray *buf; + int cmdlen; + + g_return_val_if_fail (command != NULL, NULL); + + cmdlen = strlen (command); + buf = g_byte_array_sized_new (cmdlen + 3); + + /* Make sure there's an AT in the front */ + if (!g_str_has_prefix (command, "AT")) + g_byte_array_append (buf, (const guint8 *) "AT", 2); + g_byte_array_append (buf, (const guint8 *) command, cmdlen); + + /* Make sure there's a trailing carriage return */ + if (command[cmdlen] != '\r') + g_byte_array_append (buf, (const guint8 *) "\r", 1); + + return buf; +} + +void +mm_at_serial_port_queue_command (MMAtSerialPort *self, + const char *command, + guint32 timeout_seconds, + MMAtSerialResponseFn callback, + gpointer user_data) +{ + GByteArray *buf; + + g_return_if_fail (self != NULL); + g_return_if_fail (MM_IS_AT_SERIAL_PORT (self)); + g_return_if_fail (command != NULL); + + buf = at_command_to_byte_array (command); + g_return_if_fail (buf != NULL); + + mm_serial_port_queue_command (MM_SERIAL_PORT (self), + buf, + TRUE, + timeout_seconds, + G_CALLBACK (callback), + user_data); +} + +void +mm_at_serial_port_queue_command_cached (MMAtSerialPort *self, + const char *command, + guint32 timeout_seconds, + MMAtSerialResponseFn callback, + gpointer user_data) +{ + GByteArray *buf; + + g_return_if_fail (self != NULL); + g_return_if_fail (MM_IS_AT_SERIAL_PORT (self)); + g_return_if_fail (command != NULL); + + buf = at_command_to_byte_array (command); + g_return_if_fail (buf != NULL); + + mm_serial_port_queue_command_cached (MM_SERIAL_PORT (self), + buf, + TRUE, + timeout_seconds, + G_CALLBACK (callback), + user_data); +} + +/*****************************************************************************/ + +MMAtSerialPort * +mm_at_serial_port_new (const char *name, MMPortType ptype) +{ + return MM_AT_SERIAL_PORT (g_object_new (MM_TYPE_AT_SERIAL_PORT, + MM_PORT_DEVICE, name, + MM_PORT_SUBSYS, MM_PORT_SUBSYS_TTY, + MM_PORT_TYPE, ptype, + NULL)); +} + +static void +mm_at_serial_port_init (MMAtSerialPort *self) +{ +} + +static void +finalize (GObject *object) +{ + MMAtSerialPort *self = MM_AT_SERIAL_PORT (object); + MMAtSerialPortPrivate *priv = MM_AT_SERIAL_PORT_GET_PRIVATE (self); + + while (priv->unsolicited_msg_handlers) { + MMAtUnsolicitedMsgHandler *handler = (MMAtUnsolicitedMsgHandler *) priv->unsolicited_msg_handlers->data; + + if (handler->notify) + handler->notify (handler->user_data); + + g_regex_unref (handler->regex); + g_slice_free (MMAtUnsolicitedMsgHandler, 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_at_serial_port_parent_class)->finalize (object); +} + +static void +mm_at_serial_port_class_init (MMAtSerialPortClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MMSerialPortClass *port_class = MM_SERIAL_PORT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (MMAtSerialPortPrivate)); + + /* Virtual methods */ + object_class->finalize = finalize; + + port_class->parse_unsolicited = parse_unsolicited; + port_class->parse_response = parse_response; + port_class->handle_response = handle_response; +} diff --git a/src/mm-at-serial-port.h b/src/mm-at-serial-port.h new file mode 100644 index 00000000..5d5f13f2 --- /dev/null +++ b/src/mm-at-serial-port.h @@ -0,0 +1,85 @@ +/* -*- 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 - 2010 Red Hat, Inc. + */ + +#ifndef MM_AT_SERIAL_PORT_H +#define MM_AT_SERIAL_PORT_H + +#include <glib.h> +#include <glib/gtypes.h> +#include <glib-object.h> + +#include "mm-serial-port.h" + +#define MM_TYPE_AT_SERIAL_PORT (mm_at_serial_port_get_type ()) +#define MM_AT_SERIAL_PORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_AT_SERIAL_PORT, MMAtSerialPort)) +#define MM_AT_SERIAL_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_AT_SERIAL_PORT, MMAtSerialPortClass)) +#define MM_IS_AT_SERIAL_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_AT_SERIAL_PORT)) +#define MM_IS_AT_SERIAL_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_AT_SERIAL_PORT)) +#define MM_AT_SERIAL_PORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_AT_SERIAL_PORT, MMAtSerialPortClass)) + +typedef struct _MMAtSerialPort MMAtSerialPort; +typedef struct _MMAtSerialPortClass MMAtSerialPortClass; + +typedef gboolean (*MMAtSerialResponseParserFn) (gpointer user_data, + GString *response, + GError **error); + +typedef void (*MMAtSerialUnsolicitedMsgFn) (MMAtSerialPort *port, + GMatchInfo *match_info, + gpointer user_data); + +typedef void (*MMAtSerialResponseFn) (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data); + +struct _MMAtSerialPort { + MMSerialPort parent; +}; + +struct _MMAtSerialPortClass { + MMSerialPortClass parent; +}; + +GType mm_at_serial_port_get_type (void); + +MMAtSerialPort *mm_at_serial_port_new (const char *name, MMPortType ptype); + +void mm_at_serial_port_add_unsolicited_msg_handler (MMAtSerialPort *self, + GRegex *regex, + MMAtSerialUnsolicitedMsgFn callback, + gpointer user_data, + GDestroyNotify notify); + +void mm_at_serial_port_set_response_parser (MMAtSerialPort *self, + MMAtSerialResponseParserFn fn, + gpointer user_data, + GDestroyNotify notify); + +void mm_at_serial_port_queue_command (MMAtSerialPort *self, + const char *command, + guint32 timeout_seconds, + MMAtSerialResponseFn callback, + gpointer user_data); + +void mm_at_serial_port_queue_command_cached (MMAtSerialPort *self, + const char *command, + guint32 timeout_seconds, + MMAtSerialResponseFn callback, + gpointer user_data); + +#endif /* MM_AT_SERIAL_PORT_H */ + diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index 50cd86cb..8ec71a7a 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -23,7 +23,7 @@ #include "mm-generic-cdma.h" #include "mm-modem-cdma.h" #include "mm-modem-simple.h" -#include "mm-serial-port.h" +#include "mm-at-serial-port.h" #include "mm-errors.h" #include "mm-callback-info.h" #include "mm-serial-parsers.h" @@ -67,8 +67,8 @@ typedef struct { guint reg_state_changed_id; MMCallbackInfo *simple_connect_info; - MMSerialPort *primary; - MMSerialPort *secondary; + MMAtSerialPort *primary; + MMAtSerialPort *secondary; MMPort *data; } MMGenericCdmaPrivate; @@ -148,22 +148,22 @@ mm_generic_cdma_grab_port (MMGenericCdma *self, } port = mm_modem_base_add_port (MM_MODEM_BASE (self), subsys, name, ptype); - if (port && MM_IS_SERIAL_PORT (port)) { + if (port && MM_IS_AT_SERIAL_PORT (port)) { g_object_set (G_OBJECT (port), MM_PORT_CARRIER_DETECT, FALSE, NULL); - mm_serial_port_set_response_parser (MM_SERIAL_PORT (port), - mm_serial_parser_v1_parse, - mm_serial_parser_v1_new (), - mm_serial_parser_v1_destroy); + mm_at_serial_port_set_response_parser (MM_AT_SERIAL_PORT (port), + mm_serial_parser_v1_parse, + mm_serial_parser_v1_new (), + mm_serial_parser_v1_destroy); if (ptype == MM_PORT_TYPE_PRIMARY) { - priv->primary = MM_SERIAL_PORT (port); + priv->primary = MM_AT_SERIAL_PORT (port); if (!priv->data) { priv->data = port; g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE); } check_valid (self); } else if (ptype == MM_PORT_TYPE_SECONDARY) - priv->secondary = MM_SERIAL_PORT (port); + priv->secondary = MM_AT_SERIAL_PORT (port); } else { /* Net device (if any) is the preferred data port */ if (!priv->data || MM_IS_SERIAL_PORT (priv->data)) { @@ -215,9 +215,9 @@ release_port (MMModem *modem, const char *subsys, const char *name) check_valid (MM_GENERIC_CDMA (modem)); } -MMSerialPort * -mm_generic_cdma_get_port (MMGenericCdma *modem, - MMPortType ptype) +MMAtSerialPort * +mm_generic_cdma_get_at_port (MMGenericCdma *modem, + MMPortType ptype) { g_return_val_if_fail (MM_IS_GENERIC_CDMA (modem), NULL); g_return_val_if_fail (ptype != MM_PORT_TYPE_UNKNOWN, NULL); @@ -360,7 +360,7 @@ enable_all_done (MMModem *modem, GError *error, gpointer user_data) else { /* Open up the second port, if one exists */ if (priv->secondary) { - if (!mm_serial_port_open (priv->secondary, &info->error)) { + if (!mm_serial_port_open (MM_SERIAL_PORT (priv->secondary), &info->error)) { g_assert (info->error); goto out; } @@ -380,7 +380,7 @@ out: } static void -enable_error_reporting_done (MMSerialPort *port, +enable_error_reporting_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -399,7 +399,7 @@ enable_error_reporting_done (MMSerialPort *port, } static void -init_done (MMSerialPort *port, +init_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -419,7 +419,7 @@ init_done (MMSerialPort *port, 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_port_queue_command (port, "+CMEE=1", 3, enable_error_reporting_done, user_data); + mm_at_serial_port_queue_command (port, "+CMEE=1", 3, enable_error_reporting_done, user_data); } } @@ -439,7 +439,7 @@ flash_done (MMSerialPort *port, GError *error, gpointer user_data) return; } - mm_serial_port_queue_command (port, "Z E0 V1 X4 &C1", 3, init_done, user_data); + mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "Z E0 V1 X4 &C1", 3, init_done, user_data); } static void @@ -453,7 +453,7 @@ enable (MMModem *modem, info = mm_callback_info_new (modem, callback, user_data); - if (!mm_serial_port_open (priv->primary, &info->error)) { + if (!mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &info->error)) { g_assert (info->error); mm_callback_info_schedule (info); return; @@ -463,7 +463,7 @@ enable (MMModem *modem, MM_MODEM_STATE_ENABLING, MM_MODEM_STATE_REASON_NONE); - mm_serial_port_flash (priv->primary, 100, flash_done, info); + mm_serial_port_flash (MM_SERIAL_PORT (priv->primary), 100, flash_done, info); } static void @@ -489,7 +489,7 @@ disable_all_done (MMModem *modem, GError *error, gpointer user_data) MMGenericCdma *self = MM_GENERIC_CDMA (info->modem); MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self); - mm_serial_port_close (priv->primary); + mm_serial_port_close (MM_SERIAL_PORT (priv->primary)); mm_modem_set_state (modem, MM_MODEM_STATE_DISABLED, MM_MODEM_STATE_REASON_NONE); priv->cdma_1x_reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; @@ -546,20 +546,20 @@ disable (MMModem *modem, NULL); if (priv->secondary) - mm_serial_port_close (priv->secondary); + mm_serial_port_close (MM_SERIAL_PORT (priv->secondary)); mm_modem_set_state (MM_MODEM (info->modem), MM_MODEM_STATE_DISABLING, MM_MODEM_STATE_REASON_NONE); if (mm_port_get_connected (MM_PORT (priv->primary))) - mm_serial_port_flash (priv->primary, 1000, disable_flash_done, info); + mm_serial_port_flash (MM_SERIAL_PORT (priv->primary), 1000, disable_flash_done, info); else - disable_flash_done (priv->primary, NULL, info); + disable_flash_done (MM_SERIAL_PORT (priv->primary), NULL, info); } static void -dial_done (MMSerialPort *port, +dial_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -598,7 +598,7 @@ connect (MMModem *modem, info = mm_callback_info_new (modem, callback, user_data); command = g_strconcat ("DT", number, NULL); - mm_serial_port_queue_command (priv->primary, command, 90, dial_done, info); + mm_at_serial_port_queue_command (priv->primary, command, 90, dial_done, info); g_free (command); } @@ -648,7 +648,7 @@ disconnect (MMModem *modem, NULL); mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE); - mm_serial_port_flash (priv->primary, 1000, disconnect_flash_done, info); + mm_serial_port_flash (MM_SERIAL_PORT (priv->primary), 1000, disconnect_flash_done, info); } static void @@ -678,7 +678,7 @@ strip_response (const char *resp, const char *cmd) } static void -get_version_done (MMSerialPort *port, +get_version_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -696,7 +696,7 @@ get_version_done (MMSerialPort *port, } static void -get_model_done (MMSerialPort *port, +get_model_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -712,7 +712,7 @@ get_model_done (MMSerialPort *port, } static void -get_manufacturer_done (MMSerialPort *port, +get_manufacturer_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -734,7 +734,7 @@ get_card_info (MMModem *modem, { MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem); MMCallbackInfo *info; - MMSerialPort *port = priv->primary; + MMAtSerialPort *port = priv->primary; info = mm_callback_info_new_full (MM_MODEM (modem), card_info_invoke, @@ -753,9 +753,9 @@ get_card_info (MMModem *modem, port = priv->secondary; } - mm_serial_port_queue_command_cached (port, "+GMI", 3, get_manufacturer_done, info); - mm_serial_port_queue_command_cached (port, "+GMM", 3, get_model_done, info); - mm_serial_port_queue_command_cached (port, "+GMR", 3, get_version_done, info); + mm_at_serial_port_queue_command_cached (port, "+GMI", 3, get_manufacturer_done, info); + mm_at_serial_port_queue_command_cached (port, "+GMM", 3, get_model_done, info); + mm_at_serial_port_queue_command_cached (port, "+GMR", 3, get_version_done, info); } /*****************************************************************************/ @@ -793,7 +793,7 @@ mm_generic_cdma_update_evdo_quality (MMGenericCdma *self, guint32 quality) #define CSQ2_TRIED "csq?-tried" static void -get_signal_quality_done (MMSerialPort *port, +get_signal_quality_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -811,7 +811,7 @@ get_signal_quality_done (MMSerialPort *port, * try the other command if the first one fails. */ mm_callback_info_set_data (info, CSQ2_TRIED, GUINT_TO_POINTER (1), NULL); - mm_serial_port_queue_command (port, "+CSQ?", 3, get_signal_quality_done, info); + mm_at_serial_port_queue_command (port, "+CSQ?", 3, get_signal_quality_done, info); return; } } else { @@ -853,7 +853,7 @@ get_signal_quality (MMModemCdma *modem, { MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem); MMCallbackInfo *info; - MMSerialPort *port = priv->primary; + MMAtSerialPort *port = priv->primary; if (mm_port_get_connected (MM_PORT (priv->primary))) { if (!priv->secondary) { @@ -867,11 +867,11 @@ get_signal_quality (MMModemCdma *modem, } info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); - mm_serial_port_queue_command (port, "+CSQ", 3, get_signal_quality_done, info); + mm_at_serial_port_queue_command (port, "+CSQ", 3, get_signal_quality_done, info); } static void -get_string_done (MMSerialPort *port, +get_string_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -897,7 +897,7 @@ get_esn (MMModemCdma *modem, MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem); MMCallbackInfo *info; GError *error; - MMSerialPort *port = priv->primary; + MMAtSerialPort *port = priv->primary; if (mm_port_get_connected (MM_PORT (priv->primary))) { if (!priv->secondary) { @@ -913,7 +913,7 @@ get_esn (MMModemCdma *modem, } info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data); - mm_serial_port_queue_command_cached (port, "+GSN", 3, get_string_done, info); + mm_at_serial_port_queue_command_cached (port, "+GSN", 3, get_string_done, info); } static void @@ -997,7 +997,7 @@ convert_sid (const char *sid) } static void -serving_system_done (MMSerialPort *port, +serving_system_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -1116,7 +1116,7 @@ get_serving_system (MMModemCdma *modem, MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem); MMCallbackInfo *info; GError *error; - MMSerialPort *port = priv->primary; + MMAtSerialPort *port = priv->primary; if (mm_port_get_connected (MM_PORT (priv->primary))) { if (!priv->secondary) { @@ -1136,7 +1136,7 @@ get_serving_system (MMModemCdma *modem, G_CALLBACK (callback), user_data); - mm_serial_port_queue_command (port, "+CSS?", 3, serving_system_done, info); + mm_at_serial_port_queue_command (port, "+CSS?", 3, serving_system_done, info); } #define CDMA_1X_STATE_TAG "cdma-1x-reg-state" @@ -1298,7 +1298,7 @@ reg_state_css_response (MMModemCdma *cdma, } static void -get_analog_digital_done (MMSerialPort *port, +get_analog_digital_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -1365,7 +1365,7 @@ get_registration_state (MMModemCdma *modem, { MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem); MMCallbackInfo *info; - MMSerialPort *port = priv->primary; + MMAtSerialPort *port = priv->primary; if (mm_port_get_connected (MM_PORT (priv->primary))) { if (!priv->secondary) { @@ -1380,7 +1380,7 @@ get_registration_state (MMModemCdma *modem, } info = mm_generic_cdma_query_reg_state_callback_info_new (MM_GENERIC_CDMA (modem), callback, user_data); - mm_serial_port_queue_command (port, "+CAD?", 3, get_analog_digital_done, info); + mm_at_serial_port_queue_command (port, "+CAD?", 3, get_analog_digital_done, info); } /*****************************************************************************/ diff --git a/src/mm-generic-cdma.h b/src/mm-generic-cdma.h index 5b4a0b65..dd3aba69 100644 --- a/src/mm-generic-cdma.h +++ b/src/mm-generic-cdma.h @@ -20,7 +20,7 @@ #include "mm-modem.h" #include "mm-modem-base.h" #include "mm-modem-cdma.h" -#include "mm-serial-port.h" +#include "mm-at-serial-port.h" #include "mm-callback-info.h" #define MM_TYPE_GENERIC_CDMA (mm_generic_cdma_get_type ()) @@ -80,7 +80,7 @@ MMPort * mm_generic_cdma_grab_port (MMGenericCdma *self, gpointer user_data, GError **error); -MMSerialPort *mm_generic_cdma_get_port (MMGenericCdma *modem, MMPortType ptype); +MMAtSerialPort *mm_generic_cdma_get_at_port (MMGenericCdma *modem, MMPortType ptype); void mm_generic_cdma_update_cdma1x_quality (MMGenericCdma *self, guint32 quality); void mm_generic_cdma_update_evdo_quality (MMGenericCdma *self, guint32 quality); diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index 6f88a031..425a92f7 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -26,6 +26,7 @@ #include "mm-modem-simple.h" #include "mm-errors.h" #include "mm-callback-info.h" +#include "mm-at-serial-port.h" #include "mm-serial-parsers.h" #include "mm-modem-helpers.h" @@ -66,23 +67,23 @@ typedef struct { guint32 signal_quality; guint32 cid; - MMSerialPort *primary; - MMSerialPort *secondary; + MMAtSerialPort *primary; + MMAtSerialPort *secondary; MMPort *data; } MMGenericGsmPrivate; -static void get_registration_status (MMSerialPort *port, MMCallbackInfo *info); -static void read_operator_code_done (MMSerialPort *port, +static void get_registration_status (MMAtSerialPort *port, MMCallbackInfo *info); +static void read_operator_code_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data); -static void read_operator_name_done (MMSerialPort *port, +static void read_operator_name_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data); -static void reg_state_changed (MMSerialPort *port, +static void reg_state_changed (MMAtSerialPort *port, GMatchInfo *match_info, gpointer user_data); @@ -142,7 +143,7 @@ typedef struct { } CPinResult; static void -pin_check_done (MMSerialPort *port, +pin_check_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -219,7 +220,7 @@ mm_generic_gsm_check_pin (MMGenericGsm *modem, priv = MM_GENERIC_GSM_GET_PRIVATE (modem); info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); - mm_serial_port_queue_command (priv->primary, "+CPIN?", 3, pin_check_done, info); + mm_at_serial_port_queue_command (priv->primary, "+CPIN?", 3, pin_check_done, info); } /*****************************************************************************/ @@ -305,7 +306,7 @@ initial_pin_check_done (MMModem *modem, GError *error, gpointer user_data) } else { priv->pin_checked = TRUE; if (close_port) - mm_serial_port_close (priv->primary); + mm_serial_port_close (MM_SERIAL_PORT (priv->primary)); check_valid (MM_GENERIC_GSM (modem)); } } @@ -321,7 +322,7 @@ initial_pin_check (MMGenericGsm *self) g_return_if_fail (priv->primary != NULL); - if (mm_serial_port_open (priv->primary, &error)) + if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) mm_generic_gsm_check_pin (self, initial_pin_check_done, GUINT_TO_POINTER (TRUE)); else { g_warning ("%s: failed to open serial port: (%d) %s", @@ -357,18 +358,20 @@ mm_generic_gsm_grab_port (MMGenericGsm *self, g_return_val_if_fail (!strcmp (subsys, "net") || !strcmp (subsys, "tty"), FALSE); port = mm_modem_base_add_port (MM_MODEM_BASE (self), subsys, name, ptype); - if (port && MM_IS_SERIAL_PORT (port)) { - mm_serial_port_set_response_parser (MM_SERIAL_PORT (port), - mm_serial_parser_v1_parse, - mm_serial_parser_v1_new (), - mm_serial_parser_v1_destroy); + if (port && MM_IS_AT_SERIAL_PORT (port)) { + mm_at_serial_port_set_response_parser (MM_AT_SERIAL_PORT (port), + mm_serial_parser_v1_parse, + mm_serial_parser_v1_new (), + mm_serial_parser_v1_destroy); regex = g_regex_new ("\\r\\n\\+CREG: (\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, reg_state_changed, self, NULL); + mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), + regex, reg_state_changed, + self, NULL); g_regex_unref (regex); if (ptype == MM_PORT_TYPE_PRIMARY) { - priv->primary = MM_SERIAL_PORT (port); + priv->primary = MM_AT_SERIAL_PORT (port); if (!priv->data) { priv->data = port; g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE); @@ -378,7 +381,7 @@ mm_generic_gsm_grab_port (MMGenericGsm *self, initial_pin_check (self); } else if (ptype == MM_PORT_TYPE_SECONDARY) - priv->secondary = MM_SERIAL_PORT (port); + priv->secondary = MM_AT_SERIAL_PORT (port); } else { /* Net device (if any) is the preferred data port */ if (!priv->data || MM_IS_SERIAL_PORT (priv->data)) { @@ -475,7 +478,7 @@ mm_generic_gsm_enable_complete (MMGenericGsm *modem, } static void -enable_done (MMSerialPort *port, +enable_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -495,7 +498,7 @@ enable_done (MMSerialPort *port, } static void -init_done (MMSerialPort *port, +init_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -511,20 +514,20 @@ init_done (MMSerialPort *port, /* Ensure echo is off after the init command; some modems ignore the * E0 when it's in the same like as ATZ (Option GIO322). */ - mm_serial_port_queue_command (port, "E0 +CMEE=1", 2, NULL, NULL); + mm_at_serial_port_queue_command (port, "E0 +CMEE=1", 2, NULL, NULL); g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_INIT_CMD_OPTIONAL, &cmd, NULL); - mm_serial_port_queue_command (port, cmd, 2, NULL, NULL); + mm_at_serial_port_queue_command (port, cmd, 2, NULL, NULL); g_free (cmd); if (MM_GENERIC_GSM_GET_PRIVATE (info->modem)->unsolicited_registration) - mm_serial_port_queue_command (port, "+CREG=1", 5, NULL, NULL); + mm_at_serial_port_queue_command (port, "+CREG=1", 5, NULL, NULL); else - mm_serial_port_queue_command (port, "+CREG=0", 5, NULL, NULL); + mm_at_serial_port_queue_command (port, "+CREG=0", 5, NULL, NULL); g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_POWER_UP_CMD, &cmd, NULL); if (cmd && strlen (cmd)) - mm_serial_port_queue_command (port, cmd, 5, enable_done, user_data); + mm_at_serial_port_queue_command (port, cmd, 5, enable_done, user_data); else enable_done (port, NULL, NULL, user_data); g_free (cmd); @@ -542,7 +545,7 @@ enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data) } g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_INIT_CMD, &cmd, NULL); - mm_serial_port_queue_command (port, cmd, 3, init_done, user_data); + mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), cmd, 3, init_done, user_data); g_free (cmd); } @@ -553,7 +556,7 @@ real_do_enable (MMGenericGsm *self, MMModemFn callback, gpointer user_data) MMCallbackInfo *info; info = mm_callback_info_new (MM_MODEM (self), callback, user_data); - mm_serial_port_flash (priv->primary, 100, enable_flash_done, info); + mm_serial_port_flash (MM_SERIAL_PORT (priv->primary), 100, enable_flash_done, info); } static void @@ -567,7 +570,7 @@ enable (MMModem *modem, /* First, reset the previously used CID */ mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0); - if (!mm_serial_port_open (priv->primary, &error)) { + if (!mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) { MMCallbackInfo *info; g_assert (error); @@ -584,7 +587,7 @@ enable (MMModem *modem, } static void -disable_done (MMSerialPort *port, +disable_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -595,7 +598,7 @@ disable_done (MMSerialPort *port, if (!info->error) { MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); - mm_serial_port_close (port); + mm_serial_port_close (MM_SERIAL_PORT (port)); mm_modem_set_state (MM_MODEM (info->modem), MM_MODEM_STATE_DISABLED, MM_MODEM_STATE_REASON_NONE); @@ -629,9 +632,9 @@ disable_flash_done (MMSerialPort *port, g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_POWER_DOWN_CMD, &cmd, NULL); if (cmd && strlen (cmd)) - mm_serial_port_queue_command (port, cmd, 5, disable_done, user_data); + mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), cmd, 5, disable_done, user_data); else - disable_done (port, NULL, NULL, user_data); + disable_done (MM_AT_SERIAL_PORT (port), NULL, NULL, user_data); g_free (cmd); } @@ -662,13 +665,13 @@ disable (MMModem *modem, MM_MODEM_STATE_REASON_NONE); if (mm_port_get_connected (MM_PORT (priv->primary))) - mm_serial_port_flash (priv->primary, 1000, disable_flash_done, info); + mm_serial_port_flash (MM_SERIAL_PORT (priv->primary), 1000, disable_flash_done, info); else - disable_flash_done (priv->primary, NULL, info); + disable_flash_done (MM_SERIAL_PORT (priv->primary), NULL, info); } static void -get_string_done (MMSerialPort *port, +get_string_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -692,7 +695,7 @@ get_imei (MMModemGsmCard *modem, MMCallbackInfo *info; info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data); - mm_serial_port_queue_command_cached (priv->primary, "+CGSN", 3, get_string_done, info); + mm_at_serial_port_queue_command_cached (priv->primary, "+CGSN", 3, get_string_done, info); } static void @@ -704,7 +707,7 @@ get_imsi (MMModemGsmCard *modem, MMCallbackInfo *info; info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data); - mm_serial_port_queue_command_cached (priv->primary, "+CIMI", 3, get_string_done, info); + mm_at_serial_port_queue_command_cached (priv->primary, "+CIMI", 3, get_string_done, info); } static void @@ -735,7 +738,7 @@ strip_tag (const char *str, const char *tag) } static void -get_version_done (MMSerialPort *port, +get_version_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -752,7 +755,7 @@ get_version_done (MMSerialPort *port, } static void -get_model_done (MMSerialPort *port, +get_model_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -767,7 +770,7 @@ get_model_done (MMSerialPort *port, } static void -get_manufacturer_done (MMSerialPort *port, +get_manufacturer_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -794,9 +797,9 @@ get_card_info (MMModem *modem, G_CALLBACK (callback), user_data); - 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); + mm_at_serial_port_queue_command_cached (priv->primary, "+CGMI", 3, get_manufacturer_done, info); + mm_at_serial_port_queue_command_cached (priv->primary, "+CGMM", 3, get_model_done, info); + mm_at_serial_port_queue_command_cached (priv->primary, "+CGMR", 3, get_version_done, info); } static void @@ -808,17 +811,20 @@ pin_puk_recheck_done (MMModem *modem, GError *error, gpointer user_data) * 'modem' will be NULL. */ if (modem) { + MMGenericGsmPrivate *priv; + g_return_if_fail (MM_IS_GENERIC_GSM (modem)); + priv = MM_GENERIC_GSM_GET_PRIVATE (modem); if (close_port) - mm_serial_port_close (MM_GENERIC_GSM_GET_PRIVATE (modem)->primary); + mm_serial_port_close (MM_SERIAL_PORT (priv->primary)); } } #define PIN_CLOSE_PORT_TAG "close-port" static void -send_puk_done (MMSerialPort *port, +send_puk_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -859,11 +865,11 @@ send_puk (MMModemGsmCard *modem, "Cannot unlock device while connected"); mm_callback_info_schedule (info); return; - } else if (!mm_serial_port_is_open (priv->primary)) { + } else if (!mm_serial_port_is_open (MM_SERIAL_PORT (priv->primary))) { /* Modem may not be enabled yet, which sometimes can't be done until * the device has been unlocked. */ - if (!mm_serial_port_open (priv->primary, &info->error)) { + if (!mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &info->error)) { mm_callback_info_schedule (info); return; } @@ -873,12 +879,12 @@ send_puk (MMModemGsmCard *modem, } command = g_strdup_printf ("+CPIN=\"%s\",\"%s\"", puk, pin); - mm_serial_port_queue_command (connected ? priv->secondary : priv->primary, command, 3, send_puk_done, info); + mm_at_serial_port_queue_command (connected ? priv->secondary : priv->primary, command, 3, send_puk_done, info); g_free (command); } static void -send_pin_done (MMSerialPort *port, +send_pin_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -918,11 +924,11 @@ send_pin (MMModemGsmCard *modem, "Cannot unlock device while connected"); mm_callback_info_schedule (info); return; - } else if (!mm_serial_port_is_open (priv->primary)) { + } else if (!mm_serial_port_is_open (MM_SERIAL_PORT (priv->primary))) { /* Modem may not be enabled yet, which sometimes can't be done until * the device has been unlocked. */ - if (!mm_serial_port_open (priv->primary, &info->error)) { + if (!mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &info->error)) { mm_callback_info_schedule (info); return; } @@ -932,12 +938,12 @@ send_pin (MMModemGsmCard *modem, } command = g_strdup_printf ("+CPIN=\"%s\"", pin); - mm_serial_port_queue_command (connected ? priv->secondary : priv->primary, command, 3, send_pin_done, info); + mm_at_serial_port_queue_command (connected ? priv->secondary : priv->primary, command, 3, send_pin_done, info); g_free (command); } static void -enable_pin_done (MMSerialPort *port, +enable_pin_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -962,12 +968,12 @@ enable_pin (MMModemGsmCard *modem, 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_port_queue_command (priv->primary, command, 3, enable_pin_done, info); + mm_at_serial_port_queue_command (priv->primary, command, 3, enable_pin_done, info); g_free (command); } static void -change_pin_done (MMSerialPort *port, +change_pin_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -992,7 +998,7 @@ change_pin (MMModemGsmCard *modem, 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_port_queue_command (priv->primary, command, 3, change_pin_done, info); + mm_at_serial_port_queue_command (priv->primary, command, 3, change_pin_done, info); g_free (command); } @@ -1023,7 +1029,7 @@ parse_operator (const char *reply) } static void -read_operator_code_done (MMSerialPort *port, +read_operator_code_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -1043,7 +1049,7 @@ read_operator_code_done (MMSerialPort *port, } static void -read_operator_name_done (MMSerialPort *port, +read_operator_name_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -1108,8 +1114,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_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_at_serial_port_queue_command (priv->primary, "+COPS=3,2;+COPS?", 3, read_operator_code_done, modem); + mm_at_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); @@ -1187,7 +1193,7 @@ reg_status_updated (MMGenericGsm *self, int new_value, GError **error) } static void -reg_state_changed (MMSerialPort *port, +reg_state_changed (MMAtSerialPort *port, GMatchInfo *match_info, gpointer user_data) { @@ -1237,7 +1243,7 @@ reg_status_again_remove (gpointer data) } static void -get_reg_status_done (MMSerialPort *port, +get_reg_status_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -1314,13 +1320,13 @@ reg_done: } static void -get_registration_status (MMSerialPort *port, MMCallbackInfo *info) +get_registration_status (MMAtSerialPort *port, MMCallbackInfo *info) { - mm_serial_port_queue_command (port, "+CREG?", 10, get_reg_status_done, info); + mm_at_serial_port_queue_command (port, "+CREG?", 10, get_reg_status_done, info); } static void -register_done (MMSerialPort *port, +register_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -1401,7 +1407,7 @@ do_register (MMModemGsmNetwork *modem, * the +COPS response is never received. */ mm_callback_info_ref (info); - mm_serial_port_queue_command (priv->primary, command, 120, register_done, info); + mm_at_serial_port_queue_command (priv->primary, command, 120, register_done, info); g_free (command); } @@ -1476,7 +1482,7 @@ mm_generic_gsm_connect_complete (MMGenericGsm *modem, } static void -connect_report_done (MMSerialPort *port, +connect_report_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -1507,7 +1513,7 @@ connect_report_done (MMSerialPort *port, } static void -connect_done (MMSerialPort *port, +connect_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -1519,7 +1525,7 @@ connect_done (MMSerialPort *port, info->error = g_error_copy (error); /* Try to get more information why it failed */ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); - mm_serial_port_queue_command (priv->primary, "+CEER", 3, connect_report_done, info); + mm_at_serial_port_queue_command (priv->primary, "+CEER", 3, connect_report_done, info); } else mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), NULL, info); } @@ -1553,7 +1559,7 @@ connect (MMModem *modem, } else command = g_strconcat ("DT", number, NULL); - mm_serial_port_queue_command (priv->primary, command, 60, connect_done, info); + mm_at_serial_port_queue_command (priv->primary, command, 60, connect_done, info); g_free (command); } @@ -1607,7 +1613,7 @@ disconnect (MMModem *modem, NULL); mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE); - mm_serial_port_flash (priv->primary, 1000, disconnect_flash_done, info); + mm_serial_port_flash (MM_SERIAL_PORT (priv->primary), 1000, disconnect_flash_done, info); } static void @@ -1622,7 +1628,7 @@ gsm_network_scan_invoke (MMCallbackInfo *info) } static void -scan_done (MMSerialPort *port, +scan_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -1654,13 +1660,13 @@ scan (MMModemGsmNetwork *modem, G_CALLBACK (callback), user_data); - mm_serial_port_queue_command (priv->primary, "+COPS=?", 120, scan_done, info); + mm_at_serial_port_queue_command (priv->primary, "+COPS=?", 120, scan_done, info); } /* SetApn */ static void -set_apn_done (MMSerialPort *port, +set_apn_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -1677,7 +1683,7 @@ set_apn_done (MMSerialPort *port, } static void -cid_range_read (MMSerialPort *port, +cid_range_read (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -1737,13 +1743,13 @@ cid_range_read (MMSerialPort *port, mm_callback_info_set_data (info, "cid", GUINT_TO_POINTER (cid), NULL); command = g_strdup_printf ("+CGDCONT=%d,\"IP\",\"%s\"", cid, apn); - mm_serial_port_queue_command (port, command, 3, set_apn_done, info); + mm_at_serial_port_queue_command (port, command, 3, set_apn_done, info); g_free (command); } } static void -existing_apns_read (MMSerialPort *port, +existing_apns_read (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -1808,7 +1814,7 @@ existing_apns_read (MMSerialPort *port, mm_callback_info_schedule (info); else /* APN not configured on the card. Get the allowed CID range */ - mm_serial_port_queue_command_cached (port, "+CGDCONT=?", 3, cid_range_read, info); + mm_at_serial_port_queue_command_cached (port, "+CGDCONT=?", 3, cid_range_read, info); } static void @@ -1824,13 +1830,13 @@ set_apn (MMModemGsmNetwork *modem, mm_callback_info_set_data (info, "apn", g_strdup (apn), g_free); /* Start by searching if the APN is already in card */ - mm_serial_port_queue_command (priv->primary, "+CGDCONT?", 3, existing_apns_read, info); + mm_at_serial_port_queue_command (priv->primary, "+CGDCONT?", 3, existing_apns_read, info); } /* GetSignalQuality */ static void -get_signal_quality_done (MMSerialPort *port, +get_signal_quality_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -1887,14 +1893,14 @@ get_signal_quality (MMModemGsmNetwork *modem, } info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); - mm_serial_port_queue_command (connected ? priv->secondary : priv->primary, "+CSQ", 3, get_signal_quality_done, info); + mm_at_serial_port_queue_command (connected ? priv->secondary : priv->primary, "+CSQ", 3, get_signal_quality_done, info); } /*****************************************************************************/ /* MMModemGsmSms interface */ static void -sms_send_done (MMSerialPort *port, +sms_send_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -1921,7 +1927,7 @@ sms_send (MMModemGsmSms *modem, MMCallbackInfo *info; char *command; gboolean connected; - MMSerialPort *port = NULL; + MMAtSerialPort *port = NULL; info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); @@ -1940,16 +1946,16 @@ sms_send (MMModemGsmSms *modem, } /* FIXME: use the PDU mode instead */ - mm_serial_port_queue_command (port, "AT+CMGF=1", 3, NULL, NULL); + mm_at_serial_port_queue_command (port, "AT+CMGF=1", 3, NULL, NULL); command = g_strdup_printf ("+CMGS=\"%s\"\r%s\x1a", number, text); - mm_serial_port_queue_command (port, command, 10, sms_send_done, info); + mm_at_serial_port_queue_command (port, command, 10, sms_send_done, info); g_free (command); } -MMSerialPort * -mm_generic_gsm_get_port (MMGenericGsm *modem, - MMPortType ptype) +MMAtSerialPort * +mm_generic_gsm_get_at_port (MMGenericGsm *modem, + MMPortType ptype) { g_return_val_if_fail (MM_IS_GENERIC_GSM (modem), NULL); g_return_val_if_fail (ptype != MM_PORT_TYPE_UNKNOWN, NULL); diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h index de0b00b7..b587d3a1 100644 --- a/src/mm-generic-gsm.h +++ b/src/mm-generic-gsm.h @@ -20,7 +20,7 @@ #include "mm-modem-gsm.h" #include "mm-modem-gsm-network.h" #include "mm-modem-base.h" -#include "mm-serial-port.h" +#include "mm-at-serial-port.h" #include "mm-callback-info.h" #define MM_TYPE_GENERIC_GSM (mm_generic_gsm_get_type ()) @@ -90,8 +90,8 @@ void mm_generic_gsm_check_pin (MMGenericGsm *modem, MMModemFn callback, gpointer user_data); -MMSerialPort *mm_generic_gsm_get_port (MMGenericGsm *modem, - MMPortType ptype); +MMAtSerialPort *mm_generic_gsm_get_at_port (MMGenericGsm *modem, + MMPortType ptype); MMPort *mm_generic_gsm_grab_port (MMGenericGsm *modem, const char *subsys, diff --git a/src/mm-manager.c b/src/mm-manager.c index 389acba1..9576766c 100644 --- a/src/mm-manager.c +++ b/src/mm-manager.c @@ -520,7 +520,7 @@ device_added (MMManager *manager, GUdevDevice *device) /* ignore VTs */ if (strncmp (name, "tty", 3) == 0 && isdigit (name[3])) - return; + return; if (find_modem_for_port (manager, subsys, name)) return; @@ -633,12 +633,18 @@ mm_manager_start (MMManager *manager) priv = MM_MANAGER_GET_PRIVATE (manager); devices = g_udev_client_query_by_subsystem (priv->udev, "tty"); - for (iter = devices; iter; iter = g_list_next (iter)) + for (iter = devices; iter; iter = g_list_next (iter)) { device_added (manager, G_UDEV_DEVICE (iter->data)); + g_object_unref (G_OBJECT (iter->data)); + } + g_list_free (devices); devices = g_udev_client_query_by_subsystem (priv->udev, "net"); - for (iter = devices; iter; iter = g_list_next (iter)) + for (iter = devices; iter; iter = g_list_next (iter)) { device_added (manager, G_UDEV_DEVICE (iter->data)); + g_object_unref (G_OBJECT (iter->data)); + } + g_list_free (devices); } static void diff --git a/src/mm-modem-base.c b/src/mm-modem-base.c index af1c6258..20ba2a4c 100644 --- a/src/mm-modem-base.c +++ b/src/mm-modem-base.c @@ -21,7 +21,7 @@ #include "mm-modem-base.h" #include "mm-modem.h" -#include "mm-serial-port.h" +#include "mm-at-serial-port.h" #include "mm-errors.h" #include "mm-options.h" #include "mm-properties-changed-signal.h" @@ -115,7 +115,7 @@ mm_modem_base_add_port (MMModemBase *self, } if (!strcmp (subsys, "tty")) - port = MM_PORT (mm_serial_port_new (name, ptype)); + port = MM_PORT (mm_at_serial_port_new (name, ptype)); else if (!strcmp (subsys, "net")) { port = MM_PORT (g_object_new (MM_TYPE_PORT, MM_PORT_DEVICE, name, diff --git a/src/mm-plugin-base.c b/src/mm-plugin-base.c index 202eaac9..da24e840 100644 --- a/src/mm-plugin-base.c +++ b/src/mm-plugin-base.c @@ -26,7 +26,7 @@ #include <gudev/gudev.h> #include "mm-plugin-base.h" -#include "mm-serial-port.h" +#include "mm-at-serial-port.h" #include "mm-serial-parsers.h" #include "mm-errors.h" #include "mm-marshal.h" @@ -92,7 +92,7 @@ typedef struct { guint open_id; guint32 open_tries; - MMSerialPort *probe_port; + MMAtSerialPort *probe_port; guint32 probed_caps; ProbeState probe_state; guint probe_id; @@ -378,7 +378,7 @@ probe_complete (MMPluginBaseSupportsTask *task) } static void -parse_response (MMSerialPort *port, +parse_response (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data); @@ -391,7 +391,7 @@ real_handle_probe_response (MMPluginBase *self, const GError *error) { MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task); - MMSerialPort *port = task_priv->probe_port; + MMAtSerialPort *port = task_priv->probe_port; gboolean ignore_error = FALSE; /* Some modems (Huawei E160g) won't respond to +GCAP with no SIM, but @@ -405,7 +405,7 @@ real_handle_probe_response (MMPluginBase *self, /* Try GCAP again */ if (task_priv->probe_state < PROBE_STATE_GCAP_TRY3) { task_priv->probe_state++; - mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, task); + mm_at_serial_port_queue_command (port, "+GCAP", 3, parse_response, task); } else { /* Otherwise, if all the GCAP tries timed out, ignore the port * as it's probably not an AT-capable port. @@ -459,19 +459,19 @@ real_handle_probe_response (MMPluginBase *self, switch (task_priv->probe_state) { case PROBE_STATE_GCAP_TRY2: case PROBE_STATE_GCAP_TRY3: - mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, task); + mm_at_serial_port_queue_command (port, "+GCAP", 3, parse_response, task); break; case PROBE_STATE_ATI: /* After the last GCAP attempt, try ATI */ - mm_serial_port_queue_command (port, "I", 3, parse_response, task); + mm_at_serial_port_queue_command (port, "I", 3, parse_response, task); break; case PROBE_STATE_CPIN: /* After the ATI attempt, try CPIN */ - mm_serial_port_queue_command (port, "+CPIN?", 3, parse_response, task); + mm_at_serial_port_queue_command (port, "+CPIN?", 3, parse_response, task); break; case PROBE_STATE_CGMM: /* After the CPIN attempt, try CGMM */ - mm_serial_port_queue_command (port, "+CGMM", 3, parse_response, task); + mm_at_serial_port_queue_command (port, "+CGMM", 3, parse_response, task); break; default: /* Probably not GSM or CDMA */ @@ -515,7 +515,7 @@ handle_probe_response (gpointer user_data) } static void -parse_response (MMSerialPort *port, +parse_response (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -545,7 +545,7 @@ parse_response (MMSerialPort *port, static void flash_done (MMSerialPort *port, GError *error, gpointer user_data); static void -custom_init_response (MMSerialPort *port, +custom_init_response (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) @@ -557,7 +557,7 @@ custom_init_response (MMSerialPort *port, task_priv->custom_init_tries++; if (task_priv->custom_init_tries < task_priv->custom_init_max_tries) { /* Try the custom command again */ - flash_done (port, NULL, user_data); + flash_done (MM_SERIAL_PORT (port), NULL, user_data); return; } else if (task_priv->custom_init_fail_if_timeout) { /* Fail the probe if the plugin wanted it and the command timed out */ @@ -569,7 +569,7 @@ custom_init_response (MMSerialPort *port, } /* Otherwise proceed to probing */ - mm_serial_port_queue_command (port, "+GCAP", 3, parse_response, user_data); + mm_at_serial_port_queue_command (port, "+GCAP", 3, parse_response, user_data); } static void @@ -583,14 +583,14 @@ flash_done (MMSerialPort *port, GError *error, gpointer user_data) if (task_priv->custom_init) { if (!delay_secs) delay_secs = 3; - mm_serial_port_queue_command (port, - task_priv->custom_init, - delay_secs, - custom_init_response, - user_data); + mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), + task_priv->custom_init, + delay_secs, + custom_init_response, + user_data); } else { /* Otherwise start normal probing */ - custom_init_response (port, NULL, NULL, user_data); + custom_init_response (MM_AT_SERIAL_PORT (port), NULL, NULL, user_data); } } @@ -603,7 +603,7 @@ try_open (gpointer user_data) task_priv->open_id = 0; - if (!mm_serial_port_open (task_priv->probe_port, &error)) { + if (!mm_serial_port_open (MM_SERIAL_PORT (task_priv->probe_port), &error)) { if (++task_priv->open_tries > 4) { /* took too long to open the port; give up */ g_warning ("(%s): failed to open after 4 tries.", @@ -629,7 +629,7 @@ try_open (gpointer user_data) g_debug ("(%s): probe requested by plugin '%s'", g_udev_device_get_name (port), mm_plugin_get_name (MM_PLUGIN (task_priv->plugin))); - mm_serial_port_flash (task_priv->probe_port, 100, flash_done, task); + mm_serial_port_flash (MM_SERIAL_PORT (task_priv->probe_port), 100, flash_done, task); } return FALSE; @@ -641,7 +641,7 @@ mm_plugin_base_probe_port (MMPluginBase *self, GError **error) { MMPluginBaseSupportsTaskPrivate *task_priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task); - MMSerialPort *serial; + MMAtSerialPort *serial; const char *name; GUdevDevice *port; @@ -654,7 +654,7 @@ mm_plugin_base_probe_port (MMPluginBase *self, name = g_udev_device_get_name (port); g_assert (name); - serial = mm_serial_port_new (name, MM_PORT_TYPE_PRIMARY); + serial = mm_at_serial_port_new (name, MM_PORT_TYPE_PRIMARY); if (serial == NULL) { g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Failed to create new serial port."); @@ -666,10 +666,10 @@ mm_plugin_base_probe_port (MMPluginBase *self, MM_PORT_CARRIER_DETECT, FALSE, NULL); - mm_serial_port_set_response_parser (serial, - mm_serial_parser_v1_parse, - mm_serial_parser_v1_new (), - mm_serial_parser_v1_destroy); + mm_at_serial_port_set_response_parser (serial, + mm_serial_parser_v1_parse, + mm_serial_parser_v1_new (), + mm_serial_parser_v1_destroy); /* Open the port */ task_priv->probe_port = serial; diff --git a/src/mm-qcdm-serial-port.c b/src/mm-qcdm-serial-port.c new file mode 100644 index 00000000..51d7c189 --- /dev/null +++ b/src/mm-qcdm-serial-port.c @@ -0,0 +1,176 @@ +/* -*- 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 - 2010 Red Hat, Inc. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include "mm-qcdm-serial-port.h" +#include "mm-errors.h" +#include "mm-options.h" +#include "libqcdm/src/com.h" +#include "libqcdm/src/utils.h" + +G_DEFINE_TYPE (MMQcdmSerialPort, mm_qcdm_serial_port, MM_TYPE_SERIAL_PORT) + +#define MM_QCDM_SERIAL_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_QCDM_SERIAL_PORT, MMQcdmSerialPortPrivate)) + +typedef struct { + gboolean foo; +} MMQcdmSerialPortPrivate; + + +/*****************************************************************************/ + +static gboolean +parse_response (MMSerialPort *port, GByteArray *response, GError **error) +{ + int i; + + /* Look for the QCDM packet termination character; if we found it, treat + * the buffer as a qcdm command. + */ + for (i = 0; i < response->len; i++) { + if (response->data[i] == 0x7E) + return TRUE; + } + + /* Otherwise, need more data from the device */ + return FALSE; +} + +static void +handle_response (MMSerialPort *port, + GByteArray *response, + GError *error, + GCallback callback, + gpointer callback_data) +{ + MMQcdmSerialResponseFn response_callback = (MMQcdmSerialResponseFn) callback; + GByteArray *unescaped = NULL; + gboolean escaping = FALSE; + GError *dm_error = NULL; + + if (!error) { + unescaped = g_byte_array_sized_new (response->len); + unescaped->len = dm_unescape ((const char *) response->data, response->len, + (char *) unescaped->data, unescaped->len, + &escaping); + if (unescaped->len == 0) { + g_set_error_literal (&dm_error, 0, 0, "Failed to unescape QCDM packet."); + g_byte_array_free (unescaped, TRUE); + unescaped = NULL; + } + } + + response_callback (MM_QCDM_SERIAL_PORT (port), + unescaped, + dm_error ? dm_error : error, + callback_data); + + if (unescaped) + g_byte_array_free (unescaped, TRUE); +} + +/*****************************************************************************/ + +void +mm_qcdm_serial_port_queue_command (MMQcdmSerialPort *self, + GByteArray *command, + guint32 timeout_seconds, + MMQcdmSerialResponseFn callback, + gpointer user_data) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (MM_IS_QCDM_SERIAL_PORT (self)); + g_return_if_fail (command != NULL); + + /* 'command' is expected to be already CRC-ed and escaped */ + mm_serial_port_queue_command (MM_SERIAL_PORT (self), + command, + TRUE, + timeout_seconds, + G_CALLBACK (callback), + user_data); +} + +void +mm_qcdm_serial_port_queue_command_cached (MMQcdmSerialPort *self, + GByteArray *command, + guint32 timeout_seconds, + MMQcdmSerialResponseFn callback, + gpointer user_data) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (MM_IS_QCDM_SERIAL_PORT (self)); + g_return_if_fail (command != NULL); + + /* 'command' is expected to be already CRC-ed and escaped */ + mm_serial_port_queue_command_cached (MM_SERIAL_PORT (self), + command, + TRUE, + timeout_seconds, + G_CALLBACK (callback), + user_data); +} + +/*****************************************************************************/ + +static gboolean +config_fd (MMSerialPort *port, int fd, GError **error) +{ + return qcdm_port_setup (fd, error); +} + +/*****************************************************************************/ + +MMQcdmSerialPort * +mm_qcdm_serial_port_new (const char *name, MMPortType ptype) +{ + return MM_QCDM_SERIAL_PORT (g_object_new (MM_TYPE_QCDM_SERIAL_PORT, + MM_PORT_DEVICE, name, + MM_PORT_SUBSYS, MM_PORT_SUBSYS_TTY, + MM_PORT_TYPE, ptype, + NULL)); +} + +static void +mm_qcdm_serial_port_init (MMQcdmSerialPort *self) +{ +} + +static void +finalize (GObject *object) +{ + G_OBJECT_CLASS (mm_qcdm_serial_port_parent_class)->finalize (object); +} + +static void +mm_qcdm_serial_port_class_init (MMQcdmSerialPortClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MMSerialPortClass *port_class = MM_SERIAL_PORT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (MMQcdmSerialPortPrivate)); + + /* Virtual methods */ + object_class->finalize = finalize; + + port_class->parse_response = parse_response; + port_class->handle_response = handle_response; + port_class->config_fd = config_fd; +} diff --git a/src/mm-qcdm-serial-port.h b/src/mm-qcdm-serial-port.h new file mode 100644 index 00000000..e70e124b --- /dev/null +++ b/src/mm-qcdm-serial-port.h @@ -0,0 +1,66 @@ +/* -*- 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 - 2010 Red Hat, Inc. + */ + +#ifndef MM_QCDM_SERIAL_PORT_H +#define MM_QCDM_SERIAL_PORT_H + +#include <glib.h> +#include <glib/gtypes.h> +#include <glib-object.h> + +#include "mm-serial-port.h" + +#define MM_TYPE_QCDM_SERIAL_PORT (mm_qcdm_serial_port_get_type ()) +#define MM_QCDM_SERIAL_PORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_QCDM_SERIAL_PORT, MMQcdmSerialPort)) +#define MM_QCDM_SERIAL_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_QCDM_SERIAL_PORT, MMQcdmSerialPortClass)) +#define MM_IS_QCDM_SERIAL_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_QCDM_SERIAL_PORT)) +#define MM_IS_QCDM_SERIAL_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_QCDM_SERIAL_PORT)) +#define MM_QCDM_SERIAL_PORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_QCDM_SERIAL_PORT, MMQcdmSerialPortClass)) + +typedef struct _MMQcdmSerialPort MMQcdmSerialPort; +typedef struct _MMQcdmSerialPortClass MMQcdmSerialPortClass; + +typedef void (*MMQcdmSerialResponseFn) (MMQcdmSerialPort *port, + GByteArray *response, + GError *error, + gpointer user_data); + +struct _MMQcdmSerialPort { + MMSerialPort parent; +}; + +struct _MMQcdmSerialPortClass { + MMSerialPortClass parent; +}; + +GType mm_qcdm_serial_port_get_type (void); + +MMQcdmSerialPort *mm_qcdm_serial_port_new (const char *name, MMPortType ptype); + +void mm_qcdm_serial_port_queue_command (MMQcdmSerialPort *self, + GByteArray *command, + guint32 timeout_seconds, + MMQcdmSerialResponseFn callback, + gpointer user_data); + +void mm_qcdm_serial_port_queue_command_cached (MMQcdmSerialPort *self, + GByteArray *command, + guint32 timeout_seconds, + MMQcdmSerialResponseFn callback, + gpointer user_data); + +#endif /* MM_QCDM_SERIAL_PORT_H */ + diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c index 07010e1d..a31e4299 100644 --- a/src/mm-serial-port.c +++ b/src/mm-serial-port.c @@ -55,16 +55,7 @@ typedef struct { GHashTable *reply_cache; GIOChannel *channel; GQueue *queue; - GString *command; - GString *response; - - gboolean connected; - - /* Response parser data */ - MMSerialResponseParserFn response_parser_fn; - gpointer response_parser_user_data; - GDestroyNotify response_parser_notify; - GSList *unsolicited_msg_handlers; + GByteArray *response; struct termios old_t; @@ -165,33 +156,6 @@ mm_serial_port_print_config (MMSerialPort *port, const char *detail) } #endif -typedef struct { - GRegex *regex; - MMSerialUnsolicitedMsgFn callback; - gpointer user_data; - GDestroyNotify notify; -} MMUnsolicitedMsgHandler; - -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) { @@ -327,7 +291,7 @@ parse_stopbits (guint i) } static gboolean -config_fd (MMSerialPort *self, GError **error) +real_config_fd (MMSerialPort *self, int fd, GError **error) { MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self); struct termio stbuf; @@ -342,7 +306,7 @@ config_fd (MMSerialPort *self, GError **error) stopbits = parse_stopbits (priv->stopbits); memset (&stbuf, 0, sizeof (struct termio)); - if (ioctl (priv->fd, TCGETA, &stbuf) != 0) { + if (ioctl (fd, TCGETA, &stbuf) != 0) { g_warning ("%s (%s): TCGETA error: %d", __func__, mm_port_get_device (MM_PORT (self)), @@ -360,7 +324,7 @@ config_fd (MMSerialPort *self, GError **error) stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | CLOCAL | PARENB); stbuf.c_cflag |= (speed | bits | CREAD | 0 | parity | stopbits); - if (ioctl (priv->fd, TCSETA, &stbuf) < 0) { + if (ioctl (fd, TCSETA, &stbuf) < 0) { g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, @@ -411,13 +375,13 @@ serial_debug (MMSerialPort *self, const char *prefix, const char *buf, int len) static gboolean mm_serial_port_send_command (MMSerialPort *self, - const char *command, + GByteArray *command, GError **error) { MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self); - const char *s; - int status; + int status, i = 0; int eagain_count = 1000; + const guint8 *p; if (priv->fd < 0) { g_set_error (error, MM_SERIAL_ERROR, MM_SERIAL_SEND_FAILED, @@ -431,21 +395,15 @@ mm_serial_port_send_command (MMSerialPort *self, 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 (self, "-->", priv->command->str, -1); + serial_debug (self, "-->", (const char *) command->data, command->len); /* Only accept about 3 seconds of EAGAIN */ if (priv->send_delay > 0) eagain_count = 3000000 / priv->send_delay; - s = priv->command->str; - while (*s) { - status = write (priv->fd, s, 1); + while (i < command->len) { + p = &command->data[i]; + status = write (priv->fd, p, 1); if (status < 0) { if (errno == EAGAIN) { eagain_count--; @@ -460,18 +418,46 @@ mm_serial_port_send_command (MMSerialPort *self, break; } } else - s++; + i++; if (priv->send_delay) usleep (priv->send_delay); } - return *s == '\0'; + return i == command->len; +} + +static void +mm_serial_port_set_cached_reply (MMSerialPort *self, + const GByteArray *command, + const GByteArray *response) +{ + MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self); + + g_return_if_fail (self != NULL); + g_return_if_fail (MM_IS_SERIAL_PORT (self)); + g_return_if_fail (command != NULL); + + if (response) { + GByteArray *cmd_copy = g_byte_array_sized_new (command->len); + GByteArray *rsp_copy = g_byte_array_sized_new (response->len); + + g_byte_array_append (cmd_copy, command->data, command->len); + g_byte_array_append (rsp_copy, response->data, response->len); + g_hash_table_insert (priv->reply_cache, cmd_copy, rsp_copy); + } else + g_hash_table_remove (MM_SERIAL_PORT_GET_PRIVATE (self)->reply_cache, command); +} + +static const GByteArray * +mm_serial_port_get_cached_reply (MMSerialPort *self, GByteArray *command) +{ + return (const GByteArray *) g_hash_table_lookup (MM_SERIAL_PORT_GET_PRIVATE (self)->reply_cache, command); } typedef struct { - char *command; - MMSerialResponseFn callback; + GByteArray *command; + GCallback callback; gpointer user_data; guint32 timeout; gboolean cached; @@ -514,19 +500,24 @@ mm_serial_port_got_response (MMSerialPort *self, GError *error) 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); + mm_serial_port_set_cached_reply (self, info->command, priv->response); - if (info->callback) - info->callback (self, priv->response, error, info->user_data); + g_warn_if_fail (MM_SERIAL_PORT_GET_CLASS (self)->handle_response != NULL); + MM_SERIAL_PORT_GET_CLASS (self)->handle_response (self, + priv->response, + error, + info->callback, + info->user_data); - g_free (info->command); + g_byte_array_free (info->command, TRUE); g_slice_free (MMQueueData, info); } if (error) g_error_free (error); - g_string_truncate (priv->response, 0); + if (priv->response->len) + g_byte_array_remove_range (priv->response, 0, priv->response->len); if (!g_queue_is_empty (priv->queue)) mm_serial_port_schedule_queue_process (self); } @@ -566,10 +557,10 @@ mm_serial_port_queue_process (gpointer data) return FALSE; if (info->cached) { - const char *cached = mm_serial_port_get_cached_reply (self, info->command); + const GByteArray *cached = mm_serial_port_get_cached_reply (self, info->command); if (cached) { - g_string_append (priv->response, cached); + g_byte_array_append (priv->response, cached->data, cached->len); mm_serial_port_got_response (self, NULL); return FALSE; } @@ -590,111 +581,16 @@ mm_serial_port_queue_process (gpointer data) 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, + GByteArray *response, GError **error) { - MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self); - - g_return_val_if_fail (priv->response_parser_fn != NULL, FALSE); + if (MM_SERIAL_PORT_GET_CLASS (self)->parse_unsolicited) + MM_SERIAL_PORT_GET_CLASS (self)->parse_unsolicited (self, response); - parse_unsolicited_messages (self, response); - - return priv->response_parser_fn (priv->response_parser_user_data, response, error); + g_return_val_if_fail (MM_SERIAL_PORT_GET_CLASS (self)->parse_response, FALSE); + return MM_SERIAL_PORT_GET_CLASS (self)->parse_response (self, response, error); } static gboolean @@ -709,13 +605,15 @@ data_available (GIOChannel *source, GIOStatus status; if (condition & G_IO_HUP) { - g_string_truncate (priv->response, 0); + if (priv->response->len) + g_byte_array_remove_range (priv->response, 0, priv->response->len); mm_serial_port_close (self); return FALSE; } if (condition & G_IO_ERR) { - g_string_truncate (priv->response, 0); + if (priv->response->len) + g_byte_array_remove_range (priv->response, 0, priv->response->len); return TRUE; } @@ -735,14 +633,14 @@ data_available (GIOChannel *source, if (bytes_read > 0) { serial_debug (self, "<--", buf, bytes_read); - g_string_append_len (priv->response, buf, bytes_read); + g_byte_array_append (priv->response, (const guint8 *) buf, bytes_read); } - /* Make sure the string doesn't grow too long */ + /* Make sure the response 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_port_get_device (MM_PORT (self))); - g_string_erase (priv->response, 0, (SERIAL_BUF_SIZE / 2)); + g_byte_array_remove_range (priv->response, 0, (SERIAL_BUF_SIZE / 2)); } if (parse_response (self, priv->response, &err)) @@ -833,7 +731,8 @@ mm_serial_port_open (MMSerialPort *self, GError **error) return FALSE; } - if (!config_fd (self, error)) { + g_warn_if_fail (MM_SERIAL_PORT_GET_CLASS (self)->config_fd); + if (!MM_SERIAL_PORT_GET_CLASS (self)->config_fd (self, priv->fd, error)) { close (priv->fd); priv->fd = -1; return FALSE; @@ -865,6 +764,7 @@ void mm_serial_port_close (MMSerialPort *self) { MMSerialPortPrivate *priv; + int i; g_return_if_fail (MM_IS_SERIAL_PORT (self)); @@ -896,14 +796,24 @@ mm_serial_port_close (MMSerialPort *self) close (priv->fd); priv->fd = -1; } + + /* Clear the command queue */ + for (i = 0; i < g_queue_get_length (priv->queue); i++) { + MMQueueData *item = g_queue_peek_nth (priv->queue, i); + + g_byte_array_free (item->command, TRUE); + g_slice_free (MMQueueData, item); + } + g_queue_clear (priv->queue); } static void internal_queue_command (MMSerialPort *self, - const char *command, + GByteArray *command, + gboolean take_command, gboolean cached, guint32 timeout_seconds, - MMSerialResponseFn callback, + GCallback callback, gpointer user_data) { MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self); @@ -913,7 +823,12 @@ internal_queue_command (MMSerialPort *self, g_return_if_fail (command != NULL); info = g_slice_new0 (MMQueueData); - info->command = g_strdup (command); + if (take_command) + info->command = command; + else { + info->command = g_byte_array_sized_new (command->len); + g_byte_array_append (info->command, command->data, command->len); + } info->cached = cached; info->timeout = timeout_seconds; info->callback = callback; @@ -921,7 +836,7 @@ internal_queue_command (MMSerialPort *self, /* Clear the cached value for this command if not asking for cached value */ if (!cached) - mm_serial_port_set_cached_reply (self, command, NULL); + mm_serial_port_set_cached_reply (self, info->command, NULL); g_queue_push_tail (priv->queue, info); @@ -931,22 +846,24 @@ internal_queue_command (MMSerialPort *self, void mm_serial_port_queue_command (MMSerialPort *self, - const char *command, + GByteArray *command, + gboolean take_command, guint32 timeout_seconds, - MMSerialResponseFn callback, + GCallback callback, gpointer user_data) { - internal_queue_command (self, command, FALSE, timeout_seconds, callback, user_data); + internal_queue_command (self, command, take_command, FALSE, timeout_seconds, callback, user_data); } void mm_serial_port_queue_command_cached (MMSerialPort *self, - const char *command, + GByteArray *command, + gboolean take_command, guint32 timeout_seconds, - MMSerialResponseFn callback, + GCallback callback, gpointer user_data) { - internal_queue_command (self, command, TRUE, timeout_seconds, callback, user_data); + internal_queue_command (self, command, take_command, TRUE, timeout_seconds, callback, user_data); } typedef struct { @@ -1122,12 +1039,54 @@ mm_serial_port_new (const char *name, MMPortType ptype) NULL)); } +static gboolean +ba_equal (gconstpointer v1, gconstpointer v2) +{ + const GByteArray *a = v1; + const GByteArray *b = v2; + + if (!a && b) + return -1; + else if (a && !b) + return 1; + else if (!a && !b) + return 0; + + g_assert (a && b); + if (a->len < b->len) + return -1; + else if (a->len > b->len) + return 1; + + g_assert (a->len == b->len); + return !memcmp (a->data, b->data, a->len); +} + +static guint +ba_hash (gconstpointer v) +{ + /* 31 bit hash function */ + const GByteArray *array = v; + guint32 i, h = (const signed char) array->data[0]; + + for (i = 1; i < array->len; i++) + h = (h << 5) - h + (const signed char) array->data[i]; + + return h; +} + +static void +ba_free (gpointer v) +{ + g_byte_array_free ((GByteArray *) v, TRUE); +} + 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->reply_cache = g_hash_table_new_full (ba_hash, ba_equal, ba_free, ba_free); priv->fd = -1; priv->baud = 57600; @@ -1137,8 +1096,7 @@ mm_serial_port_init (MMSerialPort *self) priv->send_delay = 1000; priv->queue = g_queue_new (); - priv->command = g_string_new_len ("AT", SERIAL_BUF_SIZE); - priv->response = g_string_sized_new (SERIAL_BUF_SIZE); + priv->response = g_byte_array_sized_new (500); } static void @@ -1212,24 +1170,8 @@ finalize (GObject *object) MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self); g_hash_table_destroy (priv->reply_cache); + g_byte_array_free (priv->response, TRUE); g_queue_free (priv->queue); - g_string_free (priv->command, TRUE); - g_string_free (priv->response, TRUE); - - 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); } @@ -1247,6 +1189,8 @@ mm_serial_port_class_init (MMSerialPortClass *klass) object_class->dispose = dispose; object_class->finalize = finalize; + klass->config_fd = real_config_fd; + /* Properties */ g_object_class_install_property (object_class, PROP_BAUD, diff --git a/src/mm-serial-port.h b/src/mm-serial-port.h index a2697f30..c07d70c8 100644 --- a/src/mm-serial-port.h +++ b/src/mm-serial-port.h @@ -39,19 +39,6 @@ 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, GError *error, gpointer user_data); @@ -62,46 +49,69 @@ struct _MMSerialPort { struct _MMSerialPortClass { MMPortClass parent; + + /* Called for subclasses to parse unsolicited responses. If any recognized + * unsolicited response is found, it should be removed from the 'response' + * byte array before returning. + */ + void (*parse_unsolicited) (MMSerialPort *self, GByteArray *response); + + /* Called to parse the device's response to a command or determine if the + * response was an error response. If the response indicates an error, an + * appropriate error should be returned in the 'error' argument. The + * function should return FALSE if there is not enough data yet to determine + * the device's reply (whether success *or* error), and should return TRUE + * when the device's response has been recognized and parsed. + */ + gboolean (*parse_response) (MMSerialPort *self, + GByteArray *response, + GError **error); + + /* Called after parsing to allow the command response to be delivered to + * it's callback to be handled. + */ + void (*handle_response) (MMSerialPort *self, + GByteArray *response, + GError *error, + GCallback callback, + gpointer callback_data); + + /* Called to configure the serial port after it's opened. On error, should + * return FALSE and set 'error' as appropriate. + */ + gboolean (*config_fd) (MMSerialPort *self, int fd, GError **error); }; GType mm_serial_port_get_type (void); MMSerialPort *mm_serial_port_new (const char *name, MMPortType ptype); -void mm_serial_port_add_unsolicited_msg_handler (MMSerialPort *self, - GRegex *regex, - MMSerialUnsolicitedMsgFn callback, - gpointer user_data, - GDestroyNotify notify); - -void mm_serial_port_set_response_parser (MMSerialPort *self, - MMSerialResponseParserFn fn, - gpointer user_data, - GDestroyNotify notify); - gboolean mm_serial_port_is_open (MMSerialPort *self); gboolean mm_serial_port_open (MMSerialPort *self, GError **error); void mm_serial_port_close (MMSerialPort *self); + +gboolean mm_serial_port_flash (MMSerialPort *self, + guint32 flash_time, + MMSerialFlashFn callback, + gpointer user_data); +void mm_serial_port_flash_cancel (MMSerialPort *self); + void mm_serial_port_queue_command (MMSerialPort *self, - const char *command, + GByteArray *command, + gboolean take_command, guint32 timeout_seconds, - MMSerialResponseFn callback, + GCallback callback, gpointer user_data); void mm_serial_port_queue_command_cached (MMSerialPort *self, - const char *command, + GByteArray *command, + gboolean take_command, guint32 timeout_seconds, - MMSerialResponseFn callback, + GCallback callback, gpointer user_data); -gboolean mm_serial_port_flash (MMSerialPort *self, - guint32 flash_time, - MMSerialFlashFn callback, - gpointer user_data); -void mm_serial_port_flash_cancel (MMSerialPort *self); - #endif /* MM_SERIAL_PORT_H */ |