aboutsummaryrefslogtreecommitdiff
path: root/src/mm-generic-gsm.c
diff options
context:
space:
mode:
authorTambet Ingo <tambet@gmail.com>2008-07-31 09:43:00 +0300
committerTambet Ingo <tambet@gmail.com>2008-07-31 09:43:00 +0300
commitcc31458b18e8c274641cf124f5bf7ec6fe506dfb (patch)
treee4ec49a3e26cfd0f002faa76e0a6c0d180204177 /src/mm-generic-gsm.c
Initial commit.
Diffstat (limited to 'src/mm-generic-gsm.c')
-rw-r--r--src/mm-generic-gsm.c705
1 files changed, 705 insertions, 0 deletions
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
new file mode 100644
index 00000000..2713cc00
--- /dev/null
+++ b/src/mm-generic-gsm.c
@@ -0,0 +1,705 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "mm-generic-gsm.h"
+#include "mm-modem-error.h"
+#include "mm-callback-info.h"
+
+static void modem_init (MMModem *modem_class);
+
+G_DEFINE_TYPE_EXTENDED (MMGenericGsm, mm_generic_gsm, MM_TYPE_SERIAL,
+ 0, G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init))
+
+#define MM_GENERIC_GSM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_GENERIC_GSM, MMGenericGsmPrivate))
+
+typedef struct {
+ char *driver;
+ guint32 pending_id;
+} MMGenericGsmPrivate;
+
+static void register_auto (MMModem *modem, MMCallbackInfo *info);
+
+MMModem *
+mm_generic_gsm_new (const char *serial_device, const char *driver)
+{
+ g_return_val_if_fail (serial_device != NULL, NULL);
+ g_return_val_if_fail (driver != NULL, NULL);
+
+ return MM_MODEM (g_object_new (MM_TYPE_GENERIC_GSM,
+ MM_SERIAL_DEVICE, serial_device,
+ MM_MODEM_DRIVER, driver,
+ NULL));
+}
+
+/*****************************************************************************/
+
+static void
+check_pin_done (MMSerial *serial,
+ int reply_index,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ switch (reply_index) {
+ case 0:
+ /* success */
+ break;
+ case 1:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_PIN_NEEDED, "%s", "PIN needed");
+ break;
+ case 2:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_PUK_NEEDED, "%s", "PUK needed");
+ break;
+ case -1:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "PIN checking timed out.");
+ break;
+ default:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "PIN checking failed.");
+ break;
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+check_pin (MMSerial *serial, gpointer user_data)
+{
+ char *responses[] = { "READY", "SIM PIN", "SIM PUK", "ERROR", "ERR", NULL };
+ char *terminators[] = { "OK", "ERROR", "ERR", NULL };
+ guint id = 0;
+
+ if (mm_serial_send_command_string (serial, "AT+CPIN?"))
+ id = mm_serial_wait_for_reply (serial, 3, responses, terminators, check_pin_done, user_data);
+
+ if (!id) {
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "PIN checking failed.");
+ mm_callback_info_schedule (info);
+ }
+}
+
+static void
+init_done (MMSerial *serial,
+ int reply_index,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ switch (reply_index) {
+ case 0:
+ /* success */
+ check_pin (serial, user_data);
+ break;
+ case -1:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Modem initialization timed out.");
+ break;
+ default:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Modem initialization failed");
+ }
+
+ if (info->error)
+ mm_callback_info_schedule (info);
+}
+
+static void
+flash_done (MMSerial *serial, gpointer user_data)
+{
+ char *responses[] = { "OK", "ERROR", "ERR", NULL };
+ guint id = 0;
+
+ if (mm_serial_send_command_string (serial, "AT E0"))
+ id = mm_serial_wait_for_reply (serial, 10, responses, responses, init_done, user_data);
+
+ if (!id) {
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Turning modem echo off failed.");
+ mm_callback_info_schedule (info);
+ }
+}
+
+static void
+enable (MMModem *modem,
+ gboolean enable,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new (modem, callback, user_data);
+
+ if (!enable) {
+ mm_serial_close (MM_SERIAL (modem));
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ if (mm_serial_open (MM_SERIAL (modem))) {
+ guint id;
+
+ id = mm_serial_flash (MM_SERIAL (modem), 100, flash_done, info);
+ if (!id)
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "%s", "Could not communicate with serial device.");
+ } else
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Could not open serial device.");
+
+ if (info->error)
+ mm_callback_info_schedule (info);
+}
+
+static void
+set_pin_done (MMSerial *serial,
+ int reply_index,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ switch (reply_index) {
+ case 0:
+ /* success */
+ break;
+ case -1:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "%s", "Did not receive response for secret");
+ break;
+ default:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_INVALID_SECRET, "%s", "Invalid secret");
+ break;
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+set_pin (MMModem *modem,
+ const char *pin,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ char *command;
+ char *responses[] = { "OK", "ERROR", "ERR", NULL };
+ guint id = 0;
+
+ info = mm_callback_info_new (modem, callback, user_data);
+
+ command = g_strdup_printf ("AT+CPIN=\"%s\"", pin);
+ if (mm_serial_send_command_string (MM_SERIAL (modem), command))
+ id = mm_serial_wait_for_reply (MM_SERIAL (modem), 3, responses, responses, set_pin_done, info);
+
+ g_free (command);
+
+ if (!id) {
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "PIN checking failed.");
+ mm_callback_info_schedule (info);
+ }
+}
+
+static void
+register_manual_done (MMSerial *serial,
+ int reply_index,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ switch (reply_index) {
+ case 0:
+ /* success */
+ break;
+ case -1:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Manual registration timed out");
+ break;
+ default:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Manual registration failed");
+ break;
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+register_manual (MMModem *modem, const char *network_id, MMCallbackInfo *info)
+{
+ char *command;
+ char *responses[] = { "OK", "ERROR", "ERR", NULL };
+ guint id = 0;
+
+ command = g_strdup_printf ("AT+COPS=1,2,\"%s\"", network_id);
+ if (mm_serial_send_command_string (MM_SERIAL (modem), command))
+ id = mm_serial_wait_for_reply (MM_SERIAL (modem), 30, responses, responses,
+ register_manual_done, info);
+
+ g_free (command);
+
+ if (!id) {
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Manual registration failed.");
+ mm_callback_info_schedule (info);
+ }
+}
+
+static gboolean
+automatic_registration_again (gpointer data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) data;
+
+ register_auto (MM_MODEM (mm_callback_info_get_data (info, "modem")), info);
+
+ mm_callback_info_set_data (info, "modem", NULL, NULL);
+
+ return FALSE;
+}
+
+static void
+register_auto_done (MMSerial *serial,
+ int reply_index,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ switch (reply_index) {
+ case 0:
+ g_message ("Registered on Home network");
+ break;
+ case 1:
+ g_message ("Registered on Roaming network");
+ break;
+ case 2:
+ mm_callback_info_set_data (info, "modem", g_object_ref (serial), g_object_unref);
+ MM_GENERIC_GSM_GET_PRIVATE (serial)->pending_id = g_timeout_add (1000, automatic_registration_again, info);
+ return;
+ break;
+ case 3:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "%s", "Automatic registration failed: not registered and not searching.");
+ break;
+ case -1:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Automatic registration timed out");
+ break;
+ default:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Automatic registration failed");
+ break;
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+register_auto (MMModem *modem, MMCallbackInfo *info)
+{
+ char *responses[] = { "+CREG: 0,1", "+CREG: 0,5", "+CREG: 0,2", "+CREG: 0,0", NULL };
+ char *terminators[] = { "OK", "ERROR", "ERR", NULL };
+ guint id = 0;
+
+ if (mm_serial_send_command_string (MM_SERIAL (modem), "AT+CREG?"))
+ id = mm_serial_wait_for_reply (MM_SERIAL (modem), 60, responses, terminators,
+ register_auto_done, info);
+
+ if (!id) {
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Automatic registration failed.");
+ mm_callback_info_schedule (info);
+ }
+}
+
+static void
+do_register (MMModem *modem,
+ const char *network_id,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new (modem, callback, user_data);
+
+ if (network_id)
+ register_manual (modem, network_id, info);
+ else
+ register_auto (modem, info);
+}
+
+static void
+dial_done (MMSerial *serial,
+ int reply_index,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ switch (reply_index) {
+ case 0:
+ /* success */
+ break;
+ case 1:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dial failed: Busy");
+ break;
+ case 2:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dial failed: No dial tone");
+ break;
+ case 3:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dial failed: No carrier");
+ break;
+ case -1:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dialing timed out");
+ break;
+ default:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dialing failed");
+ break;
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+
+static void
+dial (MMModem *modem, guint cid, const char *number, MMCallbackInfo *info)
+{
+ char *command;
+ char *responses[] = { "CONNECT", "BUSY", "NO DIAL TONE", "NO CARRIER", NULL };
+ guint id = 0;
+
+ if (cid) {
+ GString *str;
+
+ str = g_string_new ("ATD");
+ if (g_str_has_suffix (number, "#"))
+ str = g_string_append_len (str, number, strlen (number) - 1);
+ else
+ str = g_string_append (str, number);
+
+ g_string_append_printf (str, "***%d#", cid);
+ command = g_string_free (str, FALSE);
+ } else
+ command = g_strconcat ("ATDT", number, NULL);
+
+ if (mm_serial_send_command_string (MM_SERIAL (modem), command))
+ id = mm_serial_wait_for_reply (MM_SERIAL (modem), 60, responses, responses, dial_done, info);
+
+ g_free (command);
+
+ if (!id) {
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Dialing failed.");
+ mm_callback_info_schedule (info);
+ }
+}
+
+static void
+set_apn_done (MMSerial *serial,
+ int reply_index,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ const char *number = (char *) mm_callback_info_get_data (info, "number");
+
+ switch (reply_index) {
+ case 0:
+ dial (MM_MODEM (serial), 1, number, info);
+ break;
+ default:
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Setting APN failed");
+ break;
+ }
+
+ if (info->error)
+ mm_callback_info_schedule (info);
+}
+
+static void
+set_apn (MMModem *modem, const char *apn, MMCallbackInfo *info)
+{
+ char *command;
+ char *responses[] = { "OK", "ERROR", NULL };
+ guint cid = 1;
+ guint id = 0;
+
+ command = g_strdup_printf ("AT+CGDCONT=%d, \"IP\", \"%s\"", cid, apn);
+ if (mm_serial_send_command_string (MM_SERIAL (modem), command))
+ id = mm_serial_wait_for_reply (MM_SERIAL (modem), 3, responses, responses, set_apn_done, info);
+
+ g_free (command);
+
+ if (!id) {
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Setting APN failed.");
+ mm_callback_info_schedule (info);
+ }
+}
+
+static void
+connect (MMModem *modem,
+ const char *number,
+ const char *apn,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new (modem, callback, user_data);
+
+ if (apn) {
+ mm_callback_info_set_data (info, "number", g_strdup (number), g_free);
+ set_apn (modem, apn, info);
+ } else
+ dial (modem, 0, number, info);
+}
+
+static void
+disconnect (MMModem *modem,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new (modem, callback, user_data);
+ mm_serial_close (MM_SERIAL (modem));
+ mm_callback_info_schedule (info);
+}
+
+static void
+scan_callback_wrapper (MMModem *modem,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemScanFn scan_fn;
+ GPtrArray *results;
+ gpointer data;
+
+ scan_fn = (MMModemScanFn) mm_callback_info_get_data (info, "scan-callback");
+ results = (GPtrArray *) mm_callback_info_get_data (info, "scan-results");
+ data = mm_callback_info_get_data (info, "scan-data");
+
+ scan_fn (modem, results, error, data);
+}
+
+static void
+destroy_scan_data (gpointer data)
+{
+ GPtrArray *results = (GPtrArray *) data;
+
+ g_ptr_array_foreach (results, (GFunc) g_hash_table_destroy, NULL);
+ g_ptr_array_free (results, TRUE);
+}
+
+static void
+scan_done (MMSerial *serial, const char *reply, gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ GPtrArray *results;
+
+ results = g_ptr_array_new ();
+
+ if (!strncmp (reply, "+COPS: ", 7)) {
+ /* Got valid reply */
+ GRegex *r;
+ GMatchInfo *match_info;
+ GError *err = NULL;
+
+ reply += 7;
+
+ /* Pattern without crazy escaping using | for matching: (|\d|,"|.+|","|.+|","|.+|",|\d|) */
+ 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);
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Could not parse scan results.");
+ goto out;
+ }
+
+ g_regex_match (r, reply, 0, &match_info);
+ while (g_match_info_matches (match_info)) {
+ GHashTable *hash;
+
+ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ g_hash_table_insert (hash, g_strdup ("status"), g_match_info_fetch (match_info, 1));
+ g_hash_table_insert (hash, g_strdup ("operator-long"), g_match_info_fetch (match_info, 2));
+ g_hash_table_insert (hash, g_strdup ("operator-short"), g_match_info_fetch (match_info, 3));
+ g_hash_table_insert (hash, g_strdup ("operator-num"), g_match_info_fetch (match_info, 4));
+
+ g_ptr_array_add (results, hash);
+ g_match_info_next (match_info, NULL);
+ }
+
+ g_match_info_free (match_info);
+ g_regex_unref (r);
+ } else
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Could not parse scan results");
+
+ mm_callback_info_set_data (info, "scan-results", results, destroy_scan_data);
+
+ out:
+ mm_callback_info_schedule (info);
+}
+
+static void
+scan (MMModem *modem,
+ MMModemScanFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ char *terminators = "\r\n";
+ guint id = 0;
+
+ info = mm_callback_info_new (modem, scan_callback_wrapper, NULL);
+ info->user_data = info;
+ mm_callback_info_set_data (info, "scan-callback", callback, NULL);
+ mm_callback_info_set_data (info, "scan-data", user_data, NULL);
+
+ if (mm_serial_send_command_string (MM_SERIAL (modem), "AT+COPS=?"))
+ id = mm_serial_get_reply (MM_SERIAL (modem), 60, terminators, scan_done, info);
+
+ if (!id) {
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Scanning failed.");
+ mm_callback_info_schedule (info);
+ }
+}
+
+static void
+get_signal_quality_done (MMSerial *serial, const char *reply, gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ guint32 result = 0;
+
+ if (!strncmp (reply, "+CSQ: ", 6)) {
+ /* Got valid reply */
+ int quality;
+ int ber;
+
+ reply += 6;
+
+ if (sscanf (reply, "%d,%d", &quality, &ber)) {
+ /* 99 means unknown */
+ if (quality != 99)
+ /* Normalize the quality */
+ result = quality * 100 / 31;
+ } else
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "%s", "Could not parse signal quality results");
+ } else
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "%s", "Could not parse signal quality results");
+
+ info->uint_result = result;
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_signal_quality (MMModem *modem,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ char *terminators = "\r\n";
+ guint id = 0;
+
+ info = mm_callback_info_uint_new (modem, callback, user_data);
+
+ if (mm_serial_send_command_string (MM_SERIAL (modem), "AT+CSQ"))
+ id = mm_serial_get_reply (MM_SERIAL (modem), 10, terminators, get_signal_quality_done, info);
+
+ if (!id) {
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Getting signal quality failed.");
+ mm_callback_info_schedule (info);
+ }
+}
+
+/*****************************************************************************/
+
+static void
+modem_init (MMModem *modem_class)
+{
+ /* interface implementation */
+ modem_class->enable = enable;
+ modem_class->set_pin = set_pin;
+ modem_class->do_register = do_register;
+ modem_class->connect = connect;
+ modem_class->disconnect = disconnect;
+ modem_class->scan = scan;
+ modem_class->get_signal_quality = get_signal_quality;
+}
+
+static void
+mm_generic_gsm_init (MMGenericGsm *self)
+{
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case MM_MODEM_PROP_DRIVER:
+ /* Construct only */
+ MM_GENERIC_GSM_GET_PRIVATE (object)->driver = g_value_dup_string (value);
+ break;
+ case MM_MODEM_PROP_DATA_DEVICE:
+ case MM_MODEM_PROP_TYPE:
+ 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)
+{
+ switch (prop_id) {
+ case MM_MODEM_PROP_DATA_DEVICE:
+ g_value_set_string (value, mm_serial_get_device (MM_SERIAL (object)));
+ break;
+ case MM_MODEM_PROP_DRIVER:
+ g_value_set_string (value, MM_GENERIC_GSM_GET_PRIVATE (object)->driver);
+ break;
+ case MM_MODEM_PROP_TYPE:
+ g_value_set_uint (value, MM_MODEM_TYPE_GSM);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+finalize (GObject *object)
+{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (object);
+
+ if (priv->pending_id) {
+ g_source_remove (priv->pending_id);
+ priv->pending_id = 0;
+ }
+
+ g_free (priv->driver);
+
+ G_OBJECT_CLASS (mm_generic_gsm_parent_class)->finalize (object);
+}
+
+static void
+mm_generic_gsm_class_init (MMGenericGsmClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMGenericGsmPrivate));
+
+ /* Virtual methods */
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+ object_class->finalize = finalize;
+
+ /* Properties */
+ g_object_class_override_property (object_class,
+ MM_MODEM_PROP_DATA_DEVICE,
+ MM_MODEM_DATA_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_TYPE,
+ MM_MODEM_TYPE);
+
+ mm_modem_install_dbus_info (G_TYPE_FROM_CLASS (klass));
+}