Initial commit.

This commit is contained in:
Tambet Ingo
2008-07-31 09:43:00 +03:00
commit cc31458b18
37 changed files with 4911 additions and 0 deletions

2
AUTHORS Normal file
View File

@@ -0,0 +1,2 @@
Tambet Ingo <tambet@gmail.com>

1
COPYING Symbolic link
View File

@@ -0,0 +1 @@
/usr/share/automake-1.10/COPYING

0
ChangeLog Normal file
View File

30
Makefile.am Normal file
View File

@@ -0,0 +1,30 @@
SUBDIRS = src plugins introspection
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = ModemManager.pc
dbusservicedir = $(DBUS_SYS_DIR)
dbusservice_DATA = org.freedesktop.ModemManager.conf
dbusactivationdir = $(datadir)/dbus-1/system-services
dbusactivation_in_files = org.freedesktop.ModemManager.service.in
dbusactivation_DATA = $(dbusactivation_in_files:.service.in=.service)
%service: %service.in
$(edit) $< >$@
edit = @sed \
-e 's|@sbindir[@]|$(sbindir)|g' \
-e 's|@sysconfdir[@]|$(sysconfdir)|g' \
-e 's|@localstatedir[@]|$(localstatedir)|g' \
-e 's|@libexecdir[@]|$(libexecdir)|g'
DISTCLEANFILES = \
ModemManager.pc \
$(dbusactivation_DATA)
EXTRA_DIST = \
ModemManager.pc.in \
$(dbusservice_DATA) \
$(dbusactivation_in_files)

12
ModemManager.pc.in Normal file
View File

@@ -0,0 +1,12 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
libgnome_serverdir=@libexecdir@
Name: ModemManager
Description: DBus service to interact with modems.
Requires: dbus-glib-1 glib-2.0
Version: @VERSION@
Cflags: -I${includedir}/ModemManager
Libs: -L${libdir} -lmm

0
NEWS Normal file
View File

0
README Normal file
View File

20
autogen.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/sh
# Run this to generate all the initial makefiles, etc.
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
REQUIRED_AUTOMAKE_VERSION=1.7
PKG_NAME=ModemManager
(test -f $srcdir/configure.in \
&& test -f $srcdir/src/mm-modem.c) || {
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
echo " top-level $PKG_NAME directory"
exit 1
}
(cd $srcdir;
autoreconf --install --symlink &&
autoreconf &&
./configure --enable-maintainer-mode $@
)

24
configure.in Normal file
View File

@@ -0,0 +1,24 @@
AC_PREREQ(2.52)
AC_INIT(ModemManager, 0.1, tambet@gmail.com, ModemManager)
AM_INIT_AUTOMAKE([])
AM_MAINTAINER_MODE
AC_CONFIG_HEADERS(config.h)
dnl Required programs
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_INSTALL
AC_PROG_LIBTOOL
PKG_CHECK_MODULES(MM, dbus-glib-1 >= 0.75 glib-2.0 >= 2.14 gmodule-2.0 gobject-2.0 hal)
AC_CONFIG_FILES([
Makefile
src/Makefile
plugins/Makefile
introspection/Makefile
ModemManager.pc
])
AC_OUTPUT

View File

@@ -0,0 +1,4 @@
EXTRA_DIST = \
mm-manager.xml \
mm-modem.xml

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/">
<interface name="org.freedesktop.ModemManager">
<method name="EnumerateDevices">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_manager_enumerate_devices"/>
<arg name="devices" type="ao" direction="out"/>
</method>
<signal name="DeviceAdded">
<arg name="device" type="o"/>
</signal>
<signal name="DeviceRemoved">
<arg name="device" type="o"/>
</signal>
</interface>
</node>

View File

@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/">
<interface name="org.freedesktop.ModemManager.Modem">
<method name="Enable">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_enable"/>
<arg name="enable" type="b" direction="in"/>
</method>
<method name="SetPin">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_set_pin"/>
<arg name="secret" type="s" direction="in"/>
</method>
<method name="Register">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_register"/>
<arg name="network_id" type="s" direction="in"/>
</method>
<method name="Connect">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_connect"/>
<arg name="number" type="s" direction="in"/>
<arg name="apn" type="s" direction="in"/>
</method>
<method name="Disconnect">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_disconnect"/>
</method>
<method name="Scan">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_scan"/>
<arg name="results" type="aa{ss}" direction="out"/>
</method>
<method name="GetSignalQuality">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_get_signal_quality"/>
<arg name="quality" type="u" direction="out"/>
</method>
<method name="SetBand">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_set_band"/>
<arg name="band" type="u" direction="in"/>
</method>
<method name="GetBand">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_get_band"/>
<arg name="band" type="u" direction="out"/>
</method>
<method name="SetNetworkMode">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_set_network_mode"/>
<arg name="mode" type="u" direction="in"/>
</method>
<method name="GetNetworkMode">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_get_network_mode"/>
<arg name="mode" type="u" direction="out"/>
</method>
<property name="DataDevice" type="s" access="read"/>
<property name="Driver" type="s" access="read"/>
<property name="Type" type="u" access="read"/>
<signal name="SignalQuality">
<arg name="quality" type="u"/>
</signal>
<signal name="NetworkMode">
<arg name="mode" type="u"/>
</signal>
</interface>
</node>

View File

@@ -0,0 +1,19 @@
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
<allow own="org.freedesktop.ModemManager"/>
<allow send_destination="org.freedesktop.ModemManager"/>
<allow send_interface="org.freedesktop.ModemManager"/>
</policy>
<policy context="default">
<deny own="org.freedesktop.ModemManager"/>
<allow send_destination="org.freedesktop.ModemManager"/>
<allow send_interface="org.freedesktop.ModemManager"/>
</policy>
<limit name="max_replies_per_connection">512</limit>
</busconfig>

View File

@@ -0,0 +1,4 @@
[D-BUS Service]
Name=org.freedesktop.ModemManager
Exec=@sbindir@/modem-manager
User=root

14
plugins/Makefile.am Normal file
View File

@@ -0,0 +1,14 @@
pkglib_LTLIBRARIES = \
libmm-plugin-huawei.la
libmm_plugin_huawei_la_SOURCES = \
mm-modem-huawei.c \
mm-modem-huawei.h \
mm-plugin-huawei.c \
mm-plugin-huawei.h
libmm_plugin_huawei_la_CPPFLAGS = \
$(MM_CFLAGS) \
-I$(top_srcdir)/src
libmm_plugin_huawei_la_LDFLAGS = -modeule -avoid-version

556
plugins/mm-modem-huawei.c Normal file
View File

@@ -0,0 +1,556 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mm-modem-huawei.h"
#include "mm-modem-error.h"
#include "mm-callback-info.h"
static MMModem *parent_class_iface = NULL;
static void modem_init (MMModem *modem_class);
G_DEFINE_TYPE_EXTENDED (MMModemHuawei, mm_modem_huawei, MM_TYPE_GENERIC_GSM,
0, G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init))
#define MM_MODEM_HUAWEI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_HUAWEI, MMModemHuaweiPrivate))
typedef struct {
MMSerial *monitor_device;
} MMModemHuaweiPrivate;
enum {
PROP_0,
PROP_MONITOR_DEVICE,
LAST_PROP
};
MMModem *
mm_modem_huawei_new (const char *data_device,
const char *monitor_device,
const char *driver)
{
g_return_val_if_fail (data_device != NULL, NULL);
g_return_val_if_fail (monitor_device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
return MM_MODEM (g_object_new (MM_TYPE_MODEM_HUAWEI,
MM_SERIAL_DEVICE, data_device,
MM_MODEM_DRIVER, driver,
MM_MODEM_HUAWEI_MONITOR_DEVICE, monitor_device,
NULL));
}
/*****************************************************************************/
static void
parse_monitor_line (MMModem *modem, char *buf)
{
char **lines;
char **iter;
lines = g_strsplit (buf, "\r\n", 0);
for (iter = lines; iter && *iter; iter++) {
char *line = *iter;
g_strstrip (line);
if (strlen (line) < 1 || line[0] != '^')
continue;
line += 1;
if (!strncmp (line, "RSSI:", 5)) {
int quality = atoi (line + 5);
if (quality == 99)
/* 99 means unknown */
quality = 0;
else
/* Normalize the quality */
quality = quality * 100 / 31;
g_debug ("Signal quality: %d", quality);
mm_modem_signal_quality (modem, (guint32) quality);
} else if (!strncmp (line, "MODE:", 5)) {
MMModemNetworkMode mode = 0;
int a;
int b;
if (sscanf (line + 5, "%d,%d", &a, &b)) {
if (a == 3 && b == 2)
mode = MM_MODEM_NETWORK_MODE_GPRS;
else if (a == 3 && b == 3)
mode = MM_MODEM_NETWORK_MODE_EDGE;
else if (a == 5 && b == 4)
mode = MM_MODEM_NETWORK_MODE_3G;
else if (a ==5 && b == 5)
mode = MM_MODEM_NETWORK_MODE_HSDPA;
if (mode) {
g_debug ("Mode: %d", mode);
mm_modem_network_mode (modem, mode);
}
}
}
}
g_strfreev (lines);
}
static gboolean
monitor_device_got_data (GIOChannel *source,
GIOCondition condition,
gpointer data)
{
gsize bytes_read;
char buf[4096];
GIOStatus status;
if (condition & G_IO_IN) {
do {
status = g_io_channel_read_chars (source, buf, 4096, &bytes_read, NULL);
if (bytes_read) {
buf[bytes_read] = '\0';
parse_monitor_line (MM_MODEM (data), buf);
}
} while (bytes_read == 4096 || status == G_IO_STATUS_AGAIN);
}
if (condition & G_IO_HUP || condition & G_IO_ERR) {
return FALSE;
}
return TRUE;
}
static void
enable (MMModem *modem,
gboolean enable,
MMModemFn callback,
gpointer user_data)
{
MMModemHuaweiPrivate *priv = MM_MODEM_HUAWEI_GET_PRIVATE (modem);
if (enable) {
GIOChannel *channel;
mm_serial_open (priv->monitor_device);
channel = mm_serial_get_io_channel (priv->monitor_device);
g_io_add_watch (channel, G_IO_IN | G_IO_ERR | G_IO_HUP,
monitor_device_got_data, modem);
g_io_channel_unref (channel);
} else
mm_serial_close (priv->monitor_device);
parent_class_iface->enable (modem, enable, callback, user_data);
}
static gboolean
parse_syscfg (const char *reply, int *mode_a, int *mode_b, guint32 *band, int *unknown1, int *unknown2)
{
if (strncmp (reply, "^SYSCFG:", 8))
return FALSE;
if (sscanf (reply + 8, "%d,%d,%x,%d,%d", mode_a, mode_b, band, unknown1, unknown2))
return TRUE;
return FALSE;
}
static void
get_network_mode_done (MMSerial *serial, const char *reply, gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
int a, b, u1, u2;
guint32 band;
if (parse_syscfg (reply, &a, &b, &band, &u1, &u2)) {
if (a == 2 && b == 1)
info->uint_result = MM_MODEM_NETWORK_MODE_PREFER_2G;
else if (a == 2 && b == 2)
info->uint_result = MM_MODEM_NETWORK_MODE_PREFER_3G;
else if (a == 13 && b == 1)
info->uint_result = MM_MODEM_NETWORK_MODE_GPRS;
else if (a == 14 && b == 2)
info->uint_result = MM_MODEM_NETWORK_MODE_3G;
}
if (info->uint_result == 0)
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
"%s", "Could not parse network mode results");
mm_callback_info_schedule (info);
}
static void
get_network_mode (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^SYSCFG?"))
id = mm_serial_get_reply (MM_SERIAL (modem), 10, terminators, get_network_mode_done, info);
if (!id) {
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Getting network mode failed.");
mm_callback_info_schedule (info);
}
}
static void
set_network_mode_done (MMSerial *serial,
int reply_index,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
switch (reply_index) {
case 0:
/* Success */
break;
default:
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Setting network mode failed");
break;
}
mm_callback_info_schedule (info);
}
static void
set_network_mode_get_done (MMSerial *serial, const char *reply, gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
int a, b, u1, u2;
guint32 band;
guint id = 0;
if (parse_syscfg (reply, &a, &b, &band, &u1, &u2)) {
char *responses[] = { "OK", "ERROR", NULL };
char *command;
a = GPOINTER_TO_INT (mm_callback_info_get_data (info, "mode-a"));
b = GPOINTER_TO_INT (mm_callback_info_get_data (info, "mode-b"));
command = g_strdup_printf ("AT^SYSCFG=%d,%d,%X,%d,%d", a, b, band, u1, u2);
if (mm_serial_send_command_string (serial, command))
id = mm_serial_wait_for_reply (serial, 3, responses, responses, set_network_mode_done, info);
g_free (command);
}
if (!id) {
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
"%s", "Could not set network mode");
mm_callback_info_schedule (info);
}
}
static void
set_network_mode (MMModem *modem,
MMModemNetworkMode mode,
MMModemFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
char *terminators = "\r\n";
guint id = 0;
info = mm_callback_info_new (modem, callback, user_data);
switch (mode) {
case MM_MODEM_NETWORK_MODE_ANY:
/* Do nothing */
mm_callback_info_schedule (info);
return;
break;
case MM_MODEM_NETWORK_MODE_GPRS:
case MM_MODEM_NETWORK_MODE_EDGE:
mm_callback_info_set_data (info, "mode-a", GINT_TO_POINTER (13), NULL);
mm_callback_info_set_data (info, "mode-b", GINT_TO_POINTER (1), NULL);
break;
case MM_MODEM_NETWORK_MODE_3G:
case MM_MODEM_NETWORK_MODE_HSDPA:
mm_callback_info_set_data (info, "mode-a", GINT_TO_POINTER (14), NULL);
mm_callback_info_set_data (info, "mode-b", GINT_TO_POINTER (2), NULL);
break;
case MM_MODEM_NETWORK_MODE_PREFER_2G:
mm_callback_info_set_data (info, "mode-a", GINT_TO_POINTER (2), NULL);
mm_callback_info_set_data (info, "mode-b", GINT_TO_POINTER (1), NULL);
break;
case MM_MODEM_NETWORK_MODE_PREFER_3G:
mm_callback_info_set_data (info, "mode-a", GINT_TO_POINTER (2), NULL);
mm_callback_info_set_data (info, "mode-b", GINT_TO_POINTER (2), NULL);
break;
default:
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Invalid mode.");
mm_callback_info_schedule (info);
return;
break;
}
if (mm_serial_send_command_string (MM_SERIAL (modem), "AT^SYSCFG?"))
id = mm_serial_get_reply (MM_SERIAL (modem), 10, terminators, set_network_mode_get_done, info);
if (!id) {
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Setting network mode failed.");
mm_callback_info_schedule (info);
}
}
static void
get_band_done (MMSerial *serial, const char *reply, gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
int a, b, u1, u2;
guint32 band;
info->uint_result = 0xdeadbeaf;
if (parse_syscfg (reply, &a, &b, &band, &u1, &u2)) {
if (band == 0x3FFFFFFF)
info->uint_result = MM_MODEM_BAND_ANY;
else if (band == 0x400380)
info->uint_result = MM_MODEM_BAND_DCS;
else if (band == 0x200000)
info->uint_result = MM_MODEM_BAND_PCS;
}
if (info->uint_result == 0xdeadbeaf) {
info->uint_result = 0;
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
"%s", "Could not parse band results");
}
mm_callback_info_schedule (info);
}
static void
get_band (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^SYSCFG?"))
id = mm_serial_get_reply (MM_SERIAL (modem), 10, terminators, get_band_done, info);
if (!id) {
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Getting band failed.");
mm_callback_info_schedule (info);
}
}
static void
set_band_done (MMSerial *serial,
int reply_index,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
switch (reply_index) {
case 0:
/* Success */
break;
default:
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Setting band failed");
break;
}
mm_callback_info_schedule (info);
}
static void
set_band_get_done (MMSerial *serial, const char *reply, gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
int a, b, u1, u2;
guint32 band;
guint id = 0;
if (parse_syscfg (reply, &a, &b, &band, &u1, &u2)) {
char *responses[] = { "OK", "ERROR", NULL };
char *command;
band = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "band"));
command = g_strdup_printf ("AT^SYSCFG=%d,%d,%X,%d,%d", a, b, band, u1, u2);
if (mm_serial_send_command_string (serial, command))
id = mm_serial_wait_for_reply (serial, 3, responses, responses, set_band_done, info);
g_free (command);
}
if (!id) {
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
"%s", "Could not set band");
mm_callback_info_schedule (info);
}
}
static void
set_band (MMModem *modem,
MMModemBand band,
MMModemFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
char *terminators = "\r\n";
guint id = 0;
info = mm_callback_info_new (modem, callback, user_data);
switch (band) {
case MM_MODEM_BAND_ANY:
mm_callback_info_set_data (info, "band", GUINT_TO_POINTER (0x3FFFFFFF), NULL);
break;
case MM_MODEM_BAND_EGSM:
case MM_MODEM_BAND_DCS:
case MM_MODEM_BAND_U2100:
mm_callback_info_set_data (info, "band", GUINT_TO_POINTER (0x400380), NULL);
break;
case MM_MODEM_BAND_PCS:
mm_callback_info_set_data (info, "band", GUINT_TO_POINTER (0x200000), NULL);
break;
default:
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Invalid band.");
mm_callback_info_schedule (info);
return;
break;
}
if (mm_serial_send_command_string (MM_SERIAL (modem), "AT^SYSCFG?"))
id = mm_serial_get_reply (MM_SERIAL (modem), 10, terminators, set_band_get_done, info);
if (!id) {
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Setting band failed.");
mm_callback_info_schedule (info);
}
}
/*****************************************************************************/
static void
modem_init (MMModem *modem_class)
{
parent_class_iface = g_type_interface_peek_parent (modem_class);
/* interface implementation */
modem_class->enable = enable;
modem_class->set_network_mode = set_network_mode;
modem_class->get_network_mode = get_network_mode;
modem_class->set_band = set_band;
modem_class->get_band = get_band;
}
static void
mm_modem_huawei_init (MMModemHuawei *self)
{
}
static GObject*
constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)
{
GObject *object;
MMModemHuaweiPrivate *priv;
object = G_OBJECT_CLASS (mm_modem_huawei_parent_class)->constructor (type,
n_construct_params,
construct_params);
if (!object)
return NULL;
priv = MM_MODEM_HUAWEI_GET_PRIVATE (object);
if (!priv->monitor_device) {
g_warning ("No monitor device provided");
g_object_unref (object);
return NULL;
}
return object;
}
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
MMModemHuaweiPrivate *priv = MM_MODEM_HUAWEI_GET_PRIVATE (object);
switch (prop_id) {
case PROP_MONITOR_DEVICE:
/* Construct only */
priv->monitor_device = MM_SERIAL (g_object_new (MM_TYPE_SERIAL,
MM_SERIAL_DEVICE, g_value_get_string (value),
NULL));
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)
{
MMModemHuaweiPrivate *priv = MM_MODEM_HUAWEI_GET_PRIVATE (object);
switch (prop_id) {
case PROP_MONITOR_DEVICE:
g_value_set_string (value, mm_serial_get_device (priv->monitor_device));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
finalize (GObject *object)
{
MMModemHuaweiPrivate *priv = MM_MODEM_HUAWEI_GET_PRIVATE (object);
if (priv->monitor_device)
g_object_unref (priv->monitor_device);
G_OBJECT_CLASS (mm_modem_huawei_parent_class)->finalize (object);
}
static void
mm_modem_huawei_class_init (MMModemHuaweiClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (object_class, sizeof (MMModemHuaweiPrivate));
/* Virtual methods */
object_class->constructor = constructor;
object_class->set_property = set_property;
object_class->get_property = get_property;
object_class->finalize = finalize;
/* Properties */
g_object_class_install_property
(object_class, PROP_MONITOR_DEVICE,
g_param_spec_string (MM_MODEM_HUAWEI_MONITOR_DEVICE,
"MonitorDevice",
"Monitor device",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}

31
plugins/mm-modem-huawei.h Normal file
View File

@@ -0,0 +1,31 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef MM_MODEM_HUAWEI_H
#define MM_MODEM_HUAWEI_H
#include "mm-generic-gsm.h"
#define MM_TYPE_MODEM_HUAWEI (mm_modem_huawei_get_type ())
#define MM_MODEM_HUAWEI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_HUAWEI, MMModemHuawei))
#define MM_MODEM_HUAWEI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_HUAWEI, MMModemHuaweiClass))
#define MM_IS_MODEM_HUAWEI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_HUAWEI))
#define MM_IS_MODEM_HUAWEI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_HUAWEI))
#define MM_MODEM_HUAWEI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_HUAWEI, MMModemHuaweiClass))
#define MM_MODEM_HUAWEI_MONITOR_DEVICE "monitor-device"
typedef struct {
MMGenericGsm parent;
} MMModemHuawei;
typedef struct {
MMGenericGsmClass parent;
} MMModemHuaweiClass;
GType mm_modem_huawei_get_type (void);
MMModem *mm_modem_huawei_new (const char *data_device,
const char *monitor_device,
const char *driver);
#endif /* MM_MODEM_HUAWEI_H */

155
plugins/mm-plugin-huawei.c Normal file
View File

@@ -0,0 +1,155 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include <string.h>
#include <gmodule.h>
#include "mm-plugin-huawei.h"
#include "mm-modem-huawei.h"
static void plugin_init (MMPlugin *plugin_class);
G_DEFINE_TYPE_EXTENDED (MMPluginHuawei, mm_plugin_huawei, G_TYPE_OBJECT,
0, G_IMPLEMENT_INTERFACE (MM_TYPE_PLUGIN, plugin_init))
int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
G_MODULE_EXPORT MMPlugin *
mm_plugin_create (void)
{
return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_HUAWEI, NULL));
}
/*****************************************************************************/
static const char *
get_name (MMPlugin *plugin)
{
return "Huawei";
}
static char **
list_supported_udis (MMPlugin *plugin, LibHalContext *hal_ctx)
{
char **supported = NULL;
char **devices;
int num_devices;
int i;
devices = libhal_find_device_by_capability (hal_ctx, "modem", &num_devices, NULL);
if (devices) {
GPtrArray *array;
array = g_ptr_array_new ();
for (i = 0; i < num_devices; i++) {
char *udi = devices[i];
if (mm_plugin_supports_udi (plugin, hal_ctx, udi))
g_ptr_array_add (array, g_strdup (udi));
}
if (array->len > 0) {
g_ptr_array_add (array, NULL);
supported = (char **) g_ptr_array_free (array, FALSE);
} else
g_ptr_array_free (array, TRUE);
}
g_strfreev (devices);
return supported;
}
static gboolean
supports_udi (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
{
char **capabilities;
char **iter;
gboolean supported = FALSE;
capabilities = libhal_device_get_property_strlist (hal_ctx, udi, "modem.command_sets", NULL);
for (iter = capabilities; iter && *iter && !supported; iter++) {
if (!strcmp (*iter, "GSM-07.07")) {
char *parent_udi;
parent_udi = libhal_device_get_property_string (hal_ctx, udi, "info.parent", NULL);
if (parent_udi) {
int vendor;
int product;
vendor = libhal_device_get_property_int (hal_ctx, parent_udi, "usb.vendor_id", NULL);
product = libhal_device_get_property_int (hal_ctx, parent_udi, "usb.product_id", NULL);
if (vendor == 0x12d1 && (product == 0x1001 || product == 0x1003 || product == 0x1004))
supported = TRUE;
libhal_free_string (parent_udi);
}
}
}
g_strfreev (capabilities);
return supported;
}
static char *
get_driver_name (LibHalContext *ctx, const char *udi)
{
char *parent_udi;
char *driver = NULL;
parent_udi = libhal_device_get_property_string (ctx, udi, "info.parent", NULL);
if (parent_udi) {
driver = libhal_device_get_property_string (ctx, parent_udi, "info.linux.driver", NULL);
libhal_free_string (parent_udi);
}
return driver;
}
static MMModem *
create_modem (MMPlugin *plugin, LibHalContext *hal_ctx, const char *udi)
{
char *data_device;
char *monitor_device;
char *driver;
MMModem *modem;
data_device = libhal_device_get_property_string (hal_ctx, udi, "serial.device", NULL);
g_return_val_if_fail (data_device != NULL, NULL);
driver = get_driver_name (hal_ctx, udi);
g_return_val_if_fail (driver != NULL, NULL);
/* FIXME: Get monitoring device from HAL */
monitor_device = "/dev/ttyUSB1";
modem = MM_MODEM (mm_modem_huawei_new (data_device, monitor_device, driver));
g_free (data_device);
g_free (driver);
return modem;
}
/*****************************************************************************/
static void
plugin_init (MMPlugin *plugin_class)
{
/* interface implementation */
plugin_class->get_name = get_name;
plugin_class->list_supported_udis = list_supported_udis;
plugin_class->supports_udi = supports_udi;
plugin_class->create_modem = create_modem;
}
static void
mm_plugin_huawei_init (MMPluginHuawei *self)
{
}
static void
mm_plugin_huawei_class_init (MMPluginHuaweiClass *klass)
{
}

View File

@@ -0,0 +1,26 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef MM_PLUGIN_HUAWEI_H
#define MM_PLUGIN_HUAWEI_H
#include "mm-plugin.h"
#include "mm-generic-gsm.h"
#define MM_TYPE_PLUGIN_HUAWEI (mm_plugin_huawei_get_type ())
#define MM_PLUGIN_HUAWEI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_HUAWEI, MMPluginHuawei))
#define MM_PLUGIN_HUAWEI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_HUAWEI, MMPluginHuaweiClass))
#define MM_IS_PLUGIN_HUAWEI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_HUAWEI))
#define MM_IS_PLUGIN_HUAWEI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_HUAWEI))
#define MM_PLUGIN_HUAWEI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_HUAWEI, MMPluginHuaweiClass))
typedef struct {
GObject parent;
} MMPluginHuawei;
typedef struct {
GObjectClass parent;
} MMPluginHuaweiClass;
GType mm_plugin_huawei_get_type (void);
#endif /* MM_PLUGIN_HUAWEI_H */

39
src/Makefile.am Normal file
View File

@@ -0,0 +1,39 @@
sbin_PROGRAMS = modem-manager
modem_manager_CPPFLAGS = \
$(MM_CFLAGS) \
-DPLUGINDIR=\"$(pkglibdir)\"
modem_manager_LDADD = \
$(MM_LIBS)
modem_manager_SOURCES = \
main.c \
mm-callback-info.c \
mm-callback-info.h \
mm-generic-cdma.c \
mm-generic-cdma.h \
mm-generic-gsm.c \
mm-generic-gsm.h \
mm-manager.c \
mm-manager.h \
mm-modem.c \
mm-modem.h \
mm-modem-error.c \
mm-modem-error.h \
mm-plugin.c \
mm-plugin.h \
mm-serial.c \
mm-serial.h
mm-manager-glue.h: $(top_srcdir)/introspection/mm-manager.xml
dbus-binding-tool --prefix=mm_manager --mode=glib-server --output=$@ $<
mm-modem-glue.h: $(top_srcdir)/introspection/mm-modem.xml
dbus-binding-tool --prefix=mm_modem --mode=glib-server --output=$@ $<
BUILT_SOURCES = \
mm-manager-glue.h \
mm-modem-glue.h
CLEANFILES = $(BUILT_SOURCES)

166
src/main.c Normal file
View File

@@ -0,0 +1,166 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include <syslog.h>
#include <dbus/dbus-glib.h>
#include "mm-manager.h"
static void
log_handler (const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer ignored)
{
int syslog_priority;
switch (log_level) {
case G_LOG_LEVEL_ERROR:
syslog_priority = LOG_CRIT;
break;
case G_LOG_LEVEL_CRITICAL:
syslog_priority = LOG_ERR;
break;
case G_LOG_LEVEL_WARNING:
syslog_priority = LOG_WARNING;
break;
case G_LOG_LEVEL_MESSAGE:
syslog_priority = LOG_NOTICE;
break;
case G_LOG_LEVEL_DEBUG:
syslog_priority = LOG_DEBUG;
break;
case G_LOG_LEVEL_INFO:
default:
syslog_priority = LOG_INFO;
break;
}
syslog (syslog_priority, "%s", message);
}
static void
logging_setup (void)
{
openlog (G_LOG_DOMAIN, LOG_CONS, LOG_DAEMON);
g_log_set_handler (G_LOG_DOMAIN,
G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
log_handler,
NULL);
}
static void
logging_shutdown (void)
{
closelog ();
}
static void
destroy_cb (DBusGProxy *proxy, gpointer user_data)
{
GMainLoop *loop = (GMainLoop *) user_data;
g_message ("disconnected from the system bus, exiting.");
g_main_loop_quit (loop);
}
static gboolean
dbus_init (GMainLoop *loop)
{
DBusGConnection *connection;
DBusGProxy *proxy;
GError *err = NULL;
int request_name_result;
connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
if (!connection) {
g_warning ("Could not get the system bus. Make sure "
"the message bus daemon is running! Message: %s",
err->message);
g_error_free (err);
return FALSE;
}
proxy = dbus_g_proxy_new_for_name (connection,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus");
if (!dbus_g_proxy_call (proxy, "RequestName", &err,
G_TYPE_STRING, MM_DBUS_SERVICE,
G_TYPE_UINT, DBUS_NAME_FLAG_DO_NOT_QUEUE,
G_TYPE_INVALID,
G_TYPE_UINT, &request_name_result,
G_TYPE_INVALID)) {
g_warning ("Could not acquire the %s service.\n"
" Message: '%s'", MM_DBUS_SERVICE, err->message);
g_error_free (err);
goto err;
}
if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
g_warning ("Could not acquire the NetworkManagerSystemSettings service "
"as it is already taken. Return: %d",
request_name_result);
goto err;
}
g_signal_connect (proxy, "destroy", G_CALLBACK (destroy_cb), loop);
return TRUE;
err:
dbus_g_connection_unref (connection);
g_object_unref (proxy);
return FALSE;
}
int
main (int argc, char *argv[])
{
GOptionContext *opt_ctx;
GError *error = NULL;
GMainLoop *loop;
MMManager *manager;
gboolean debug = FALSE;
GOptionEntry entries[] = {
{ "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Output to console rather than syslog", NULL },
{ NULL }
};
opt_ctx = g_option_context_new (NULL);
g_option_context_set_summary (opt_ctx, "DBus system service to communicate with modems.");
g_option_context_add_main_entries (opt_ctx, entries, NULL);
if (!g_option_context_parse (opt_ctx, &argc, &argv, &error)) {
g_warning ("%s\n", error->message);
g_error_free (error);
return 1;
}
g_option_context_free (opt_ctx);
g_type_init ();
if (!debug)
logging_setup ();
loop = g_main_loop_new (NULL, FALSE);
if (!dbus_init (loop))
return -1;
manager = mm_manager_new ();
g_main_loop_run (loop);
g_object_unref (manager);
logging_shutdown ();
return 0;
}

98
src/mm-callback-info.c Normal file
View File

@@ -0,0 +1,98 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "mm-callback-info.h"
#include "mm-modem-error.h"
static void
callback_info_done (gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
info->pending_id = 0;
if (info->callback)
info->callback (info->modem, info->error, info->user_data);
else if (info->uint_callback)
info->uint_callback (info->modem, info->uint_result, info->error, info->user_data);
if (info->error)
g_error_free (info->error);
g_object_unref (info->modem);
g_datalist_clear (&info->qdata);
g_slice_free (MMCallbackInfo, info);
}
static gboolean
callback_info_do (gpointer user_data)
{
/* Nothing here, everything is done in callback_info_done to make sure the info->callback
always gets called, even if the pending call gets cancelled. */
return FALSE;
}
void
mm_callback_info_schedule (MMCallbackInfo *info)
{
info->pending_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, callback_info_do, info, callback_info_done);
}
void
mm_callback_info_cancel (MMCallbackInfo *info)
{
if (info->pending_id) {
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Call cancelled");
mm_callback_info_schedule (info);
}
}
MMCallbackInfo *
mm_callback_info_new (MMModem *modem, MMModemFn callback, gpointer user_data)
{
MMCallbackInfo *info;
info = g_slice_new0 (MMCallbackInfo);
g_datalist_init (&info->qdata);
info->modem = g_object_ref (modem);
info->callback = callback;
info->user_data = user_data;
return info;
}
MMCallbackInfo *
mm_callback_info_uint_new (MMModem *modem,
MMModemUIntFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
info = g_slice_new0 (MMCallbackInfo);
g_datalist_init (&info->qdata);
info->modem = g_object_ref (modem);
info->uint_callback = callback;
info->user_data = user_data;
return info;
}
void
mm_callback_info_set_data (MMCallbackInfo *info,
const char *key,
gpointer data,
GDestroyNotify destroy)
{
g_datalist_id_set_data_full (&info->qdata, g_quark_from_string (key), data,
data ? destroy : (GDestroyNotify) NULL);
}
gpointer
mm_callback_info_get_data (MMCallbackInfo *info, const char *key)
{
GQuark quark;
quark = g_quark_try_string (key);
return quark ? g_datalist_id_get_data (&info->qdata, quark) : NULL;
}

38
src/mm-callback-info.h Normal file
View File

@@ -0,0 +1,38 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef MM_CALLBACK_INFO_H
#define MM_CALLBACK_INFO_H
#include "mm-modem.h"
typedef struct {
GData *qdata;
MMModem *modem;
MMModemFn callback;
MMModemUIntFn uint_callback;
guint32 uint_result;
gpointer user_data;
GError *error;
guint pending_id;
} MMCallbackInfo;
MMCallbackInfo *mm_callback_info_new (MMModem *modem,
MMModemFn callback,
gpointer user_data);
MMCallbackInfo *mm_callback_info_uint_new (MMModem *modem,
MMModemUIntFn callback,
gpointer user_data);
void mm_callback_info_schedule (MMCallbackInfo *info);
void mm_callback_info_cancel (MMCallbackInfo *info);
void mm_callback_info_set_data (MMCallbackInfo *info,
const char *key,
gpointer data,
GDestroyNotify destroy);
gpointer mm_callback_info_get_data (MMCallbackInfo *info,
const char *key);
#endif /* MM_CALLBACK_INFO_H */

259
src/mm-generic-cdma.c Normal file
View File

@@ -0,0 +1,259 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "mm-generic-cdma.h"
#include "mm-modem-error.h"
#include "mm-callback-info.h"
static void modem_init (MMModem *modem_class);
G_DEFINE_TYPE_EXTENDED (MMGenericCdma, mm_generic_cdma, MM_TYPE_SERIAL,
0, G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init))
#define MM_GENERIC_CDMA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_GENERIC_CDMA, MMGenericCdmaPrivate))
typedef struct {
char *driver;
} MMGenericCdmaPrivate;
MMModem *
mm_generic_cdma_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_CDMA,
MM_SERIAL_DEVICE, serial_device,
MM_MODEM_DRIVER, driver,
NULL));
}
/*****************************************************************************/
static void
init_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", "Modem initialization timed out.");
break;
default:
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "%s", "Modem initialization failed");
}
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
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
connect (MMModem *modem,
const char *number,
const char *apn,
MMModemFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
char *command;
char *responses[] = { "CONNECT", "BUSY", "NO DIAL TONE", "NO CARRIER", NULL };
guint id = 0;
info = mm_callback_info_new (modem, callback, user_data);
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
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
modem_init (MMModem *modem_class)
{
/* interface implementation */
modem_class->enable = enable;
modem_class->connect = connect;
modem_class->disconnect = disconnect;
}
static void
mm_generic_cdma_init (MMGenericCdma *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_CDMA_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_CDMA_GET_PRIVATE (object)->driver);
break;
case MM_MODEM_PROP_TYPE:
g_value_set_uint (value, MM_MODEM_TYPE_CDMA);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
finalize (GObject *object)
{
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (object);
g_free (priv->driver);
G_OBJECT_CLASS (mm_generic_cdma_parent_class)->finalize (object);
}
static void
mm_generic_cdma_class_init (MMGenericCdmaClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (object_class, sizeof (MMGenericCdmaPrivate));
/* 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));
}

29
src/mm-generic-cdma.h Normal file
View File

@@ -0,0 +1,29 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef MM_GENERIC_CDMA_H
#define MM_GENERIC_CDMA_H
#include "mm-modem.h"
#include "mm-serial.h"
#define MM_TYPE_GENERIC_CDMA (mm_generic_cdma_get_type ())
#define MM_GENERIC_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_GENERIC_CDMA, MMGenericCdma))
#define MM_GENERIC_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_GENERIC_CDMA, MMGenericCdmaClass))
#define MM_IS_GENERIC_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_GENERIC_CDMA))
#define MM_IS_GENERIC_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_GENERIC_CDMA))
#define MM_GENERIC_CDMA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_GENERIC_CDMA, MMGenericCdmaClass))
typedef struct {
MMSerial parent;
} MMGenericCdma;
typedef struct {
MMSerialClass parent;
} MMGenericCdmaClass;
GType mm_generic_cdma_get_type (void);
MMModem *mm_generic_cdma_new (const char *serial_device,
const char *driver);
#endif /* MM_GENERIC_CDMA_H */

705
src/mm-generic-gsm.c Normal file
View File

@@ -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));
}

29
src/mm-generic-gsm.h Normal file
View File

@@ -0,0 +1,29 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef MM_GENERIC_GSM_H
#define MM_GENERIC_GSM_H
#include "mm-modem.h"
#include "mm-serial.h"
#define MM_TYPE_GENERIC_GSM (mm_generic_gsm_get_type ())
#define MM_GENERIC_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_GENERIC_GSM, MMGenericGsm))
#define MM_GENERIC_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_GENERIC_GSM, MMGenericGsmClass))
#define MM_IS_GENERIC_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_GENERIC_GSM))
#define MM_IS_GENERIC_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_GENERIC_GSM))
#define MM_GENERIC_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_GENERIC_GSM, MMGenericGsmClass))
typedef struct {
MMSerial parent;
} MMGenericGsm;
typedef struct {
MMSerialClass parent;
} MMGenericGsmClass;
GType mm_generic_gsm_get_type (void);
MMModem *mm_generic_gsm_new (const char *serial_device,
const char *driver);
#endif /* MM_GENERIC_GSM_H */

457
src/mm-manager.c Normal file
View File

@@ -0,0 +1,457 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include <string.h>
#include <gmodule.h>
#include <libhal.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include "mm-manager.h"
#include "mm-modem-error.h"
#include "mm-generic-gsm.h"
#include "mm-generic-cdma.h"
#include "mm-plugin.h"
static gboolean impl_manager_enumerate_devices (MMManager *manager,
GPtrArray **devices,
GError **err);
#include "mm-manager-glue.h"
G_DEFINE_TYPE (MMManager, mm_manager, G_TYPE_OBJECT)
enum {
DEVICE_ADDED,
DEVICE_REMOVED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
#define MM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MANAGER, MMManagerPrivate))
typedef struct {
DBusGConnection *connection;
LibHalContext *hal_ctx;
GSList *plugins;
GHashTable *modems;
} MMManagerPrivate;
static MMPlugin *
load_plugin (const char *path)
{
MMPlugin *plugin = NULL;
GModule *module;
MMPluginCreateFunc plugin_create_func;
int *major_plugin_version, *minor_plugin_version;
module = g_module_open (path, G_MODULE_BIND_LAZY);
if (!module) {
g_warning ("Could not load plugin %s: %s", path, g_module_error ());
return NULL;
}
if (!g_module_symbol (module, "mm_plugin_major_version", (gpointer *) &major_plugin_version)) {
g_warning ("Could not load plugin %s: Missing major version info", path);
goto out;
}
if (*major_plugin_version != MM_PLUGIN_MAJOR_VERSION) {
g_warning ("Could not load plugin %s: Plugin major version %d, %d is required",
path, *major_plugin_version, MM_PLUGIN_MAJOR_VERSION);
goto out;
}
if (!g_module_symbol (module, "mm_plugin_minor_version", (gpointer *) &minor_plugin_version)) {
g_warning ("Could not load plugin %s: Missing minor version info", path);
goto out;
}
if (*minor_plugin_version != MM_PLUGIN_MINOR_VERSION) {
g_warning ("Could not load plugin %s: Plugin minor version %d, %d is required",
path, *minor_plugin_version, MM_PLUGIN_MINOR_VERSION);
goto out;
}
if (!g_module_symbol (module, "mm_plugin_create", (gpointer *) &plugin_create_func)) {
g_warning ("Could not load plugin %s: %s", path, g_module_error ());
goto out;
}
plugin = (*plugin_create_func) ();
if (plugin) {
g_object_weak_ref (G_OBJECT (plugin), (GWeakNotify) g_module_close, module);
g_message ("Loaded plugin %s", mm_plugin_get_name (plugin));
} else
g_warning ("Could not load plugin %s: initialization failed", path);
out:
if (!plugin)
g_module_close (module);
return plugin;
}
static void
load_plugins (MMManager *manager)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
GDir *dir;
const char *fname;
if (!g_module_supported ()) {
g_warning ("GModules are not supported on your platform!");
return;
}
dir = g_dir_open (PLUGINDIR, 0, NULL);
if (!dir) {
g_warning ("No plugins found");
return;
}
while ((fname = g_dir_read_name (dir)) != NULL) {
char *path;
MMPlugin *plugin;
if (!strstr (fname, G_MODULE_SUFFIX))
continue;
path = g_module_build_path (PLUGINDIR, fname);
plugin = load_plugin (path);
g_free (path);
if (plugin)
priv->plugins = g_slist_append (priv->plugins, plugin);
}
g_dir_close (dir);
}
MMManager *
mm_manager_new (void)
{
return g_object_new (MM_TYPE_MANAGER, NULL);
}
static char *
get_driver_name (LibHalContext *ctx, const char *udi)
{
char *parent_udi;
char *driver = NULL;
parent_udi = libhal_device_get_property_string (ctx, udi, "info.parent", NULL);
if (parent_udi) {
driver = libhal_device_get_property_string (ctx, parent_udi, "info.linux.driver", NULL);
libhal_free_string (parent_udi);
}
return driver;
}
static MMModem *
create_generic_modem (MMManager *manager, const char *udi)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
MMModem *modem;
char **capabilities;
char **iter;
char *serial_device;
char *driver;
gboolean type_gsm = FALSE;
gboolean type_cdma = FALSE;
capabilities = libhal_device_get_property_strlist (priv->hal_ctx, udi, "modem.command_sets", NULL);
for (iter = capabilities; iter && *iter; iter++) {
if (!strcmp (*iter, "GSM-07.07")) {
type_gsm = TRUE;
break;
}
if (!strcmp (*iter, "IS-707-A")) {
type_cdma = TRUE;
break;
}
}
g_strfreev (capabilities);
if (!type_gsm && !type_cdma)
return NULL;
serial_device = libhal_device_get_property_string (priv->hal_ctx, udi, "serial.device", NULL);
g_return_val_if_fail (serial_device != NULL, NULL);
driver = get_driver_name (priv->hal_ctx, udi);
g_return_val_if_fail (driver != NULL, NULL);
if (type_gsm)
modem = mm_generic_gsm_new (serial_device, driver);
else
modem = mm_generic_cdma_new (serial_device, driver);
g_free (serial_device);
g_free (driver);
return modem;
}
static void
add_modem (MMManager *manager, const char *udi, MMModem *modem)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
g_debug ("Added modem %s", udi);
g_hash_table_insert (priv->modems, g_strdup (udi), modem);
dbus_g_connection_register_g_object (priv->connection, udi, G_OBJECT (modem));
g_signal_emit (manager, signals[DEVICE_ADDED], 0, modem);
}
static MMModem *
modem_exists (MMManager *manager, const char *udi)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
return (MMModem *) g_hash_table_lookup (priv->modems, udi);
}
static void
create_initial_modems_from_plugins (MMManager *manager)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
GSList *iter;
for (iter = priv->plugins; iter; iter = iter->next) {
MMPlugin *plugin = MM_PLUGIN (iter->data);
GSList *udis;
GSList *udi_iter;
udis = mm_plugin_list_supported_udis (plugin, priv->hal_ctx);
for (udi_iter = udis; udi_iter; udi_iter = udi_iter->next) {
char *udi = (char *) udi_iter->data;
MMModem *modem;
if (modem_exists (manager, udi)) {
g_warning ("Modem for UDI %s already exists, ignoring", udi);
continue;
}
modem = mm_plugin_create_modem (plugin, priv->hal_ctx, udi);
if (modem)
add_modem (manager, udi, modem);
else
g_warning ("Plugin failed to create modem for UDI %s", udi);
}
g_slist_foreach (udis, (GFunc) g_free, NULL);
g_slist_free (udis);
}
}
static void
create_initial_modems_generic (MMManager *manager)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
char **devices;
int num_devices;
int i;
DBusError err;
dbus_error_init (&err);
devices = libhal_find_device_by_capability (priv->hal_ctx, "modem", &num_devices, &err);
if (dbus_error_is_set (&err)) {
g_warning ("Could not list HAL devices: %s", err.message);
dbus_error_free (&err);
}
if (devices) {
for (i = 0; i < num_devices; i++) {
char *udi = devices[i];
MMModem *modem;
if (modem_exists (manager, udi))
/* Already exists, most likely handled by a plugin */
continue;
modem = create_generic_modem (manager, udi);
if (modem)
add_modem (manager, g_strdup (udi), modem);
}
}
g_strfreev (devices);
}
static void
create_initial_modems (MMManager *manager)
{
create_initial_modems_from_plugins (manager);
create_initial_modems_generic (manager);
}
static void
enumerate_devices_cb (gpointer key, gpointer val, gpointer user_data)
{
GPtrArray **devices = (GPtrArray **) user_data;
g_ptr_array_add (*devices, g_strdup ((char *) key));
}
static gboolean
impl_manager_enumerate_devices (MMManager *manager,
GPtrArray **devices,
GError **err)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
*devices = g_ptr_array_sized_new (g_hash_table_size (priv->modems));
g_hash_table_foreach (priv->modems, enumerate_devices_cb, devices);
return TRUE;
}
static void
device_added (LibHalContext *ctx, const char *udi)
{
MMManager *manager = MM_MANAGER (libhal_ctx_get_user_data (ctx));
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
GSList *iter;
MMModem *modem = NULL;
if (modem_exists (manager, udi))
/* Shouldn't happen */
return;
for (iter = priv->plugins; iter && modem == NULL; iter = iter->next) {
MMPlugin *plugin = MM_PLUGIN (iter->data);
if (mm_plugin_supports_udi (plugin, ctx, udi)) {
modem = mm_plugin_create_modem (plugin, ctx, udi);
if (modem)
break;
}
}
if (!modem)
/* None of the plugins supported the udi, try generic devices */
modem = create_generic_modem (manager, udi);
if (modem)
add_modem (manager, udi, modem);
}
static void
device_removed (LibHalContext *ctx, const char *udi)
{
MMManager *manager = MM_MANAGER (libhal_ctx_get_user_data (ctx));
MMModem *modem;
modem = modem_exists (manager, udi);
if (modem) {
g_debug ("Removed modem %s", udi);
g_signal_emit (manager, signals[DEVICE_REMOVED], 0, modem);
g_hash_table_remove (MM_MANAGER_GET_PRIVATE (manager)->modems, udi);
}
}
static void
device_new_capability (LibHalContext *ctx, const char *udi, const char *capability)
{
device_added (ctx, udi);
}
static void
mm_manager_init (MMManager *manager)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
GError *err = NULL;
DBusError dbus_error;
priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
if (!priv->connection)
g_error ("Could not connect to system bus.");
dbus_g_connection_register_g_object (priv->connection,
MM_DBUS_PATH,
G_OBJECT (manager));
priv->hal_ctx = libhal_ctx_new ();
if (!priv->hal_ctx)
g_error ("Could not get connection to the HAL service.");
libhal_ctx_set_dbus_connection (priv->hal_ctx, dbus_g_connection_get_connection (priv->connection));
dbus_error_init (&dbus_error);
if (!libhal_ctx_init (priv->hal_ctx, &dbus_error))
g_error ("libhal_ctx_init() failed: %s\n"
"Make sure the hal daemon is running?",
dbus_error.message);
load_plugins (manager);
libhal_ctx_set_user_data (priv->hal_ctx, manager);
libhal_ctx_set_device_added (priv->hal_ctx, device_added);
libhal_ctx_set_device_removed (priv->hal_ctx, device_removed);
libhal_ctx_set_device_new_capability (priv->hal_ctx, device_new_capability);
create_initial_modems (manager);
}
static void
finalize (GObject *object)
{
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (object);
g_hash_table_destroy (priv->modems);
g_slist_foreach (priv->plugins, (GFunc) g_object_unref, NULL);
g_slist_free (priv->plugins);
if (priv->hal_ctx) {
libhal_ctx_shutdown (priv->hal_ctx, NULL);
libhal_ctx_free (priv->hal_ctx);
}
if (priv->connection)
dbus_g_connection_unref (priv->connection);
G_OBJECT_CLASS (mm_manager_parent_class)->finalize (object);
}
static void
mm_manager_class_init (MMManagerClass *manager_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
g_type_class_add_private (object_class, sizeof (MMManagerPrivate));
/* Virtual methods */
object_class->finalize = finalize;
/* Signals */
signals[DEVICE_ADDED] =
g_signal_new ("device-added",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (MMManagerClass, device_added),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
G_TYPE_OBJECT);
signals[DEVICE_REMOVED] =
g_signal_new ("device-removed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (MMManagerClass, device_removed),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
G_TYPE_OBJECT);
dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (manager_class),
&dbus_glib_mm_manager_object_info);
dbus_g_error_domain_register (MM_MODEM_ERROR, NULL, MM_TYPE_MODEM_ERROR);
}

36
src/mm-manager.h Normal file
View File

@@ -0,0 +1,36 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef MM_MANAGER_H
#define MM_MANAGER_H
#include <glib/gtypes.h>
#include <glib-object.h>
#include "mm-modem.h"
#define MM_TYPE_MANAGER (mm_manager_get_type ())
#define MM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MANAGER, MMManager))
#define MM_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MANAGER, MMManagerClass))
#define MM_IS_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MANAGER))
#define MM_IS_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), MM_TYPE_MANAGER))
#define MM_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MANAGER, MMManagerClass))
#define MM_DBUS_SERVICE "org.freedesktop.ModemManager"
#define MM_DBUS_PATH "/org/freedesktop/ModemManager"
typedef struct {
GObject parent;
} MMManager;
typedef struct {
GObjectClass parent;
/* Signals */
void (*device_added) (MMManager *manager, MMModem *device);
void (*device_removed) (MMManager *manager, MMModem *device);
} MMManagerClass;
GType mm_manager_get_type (void);
MMManager *mm_manager_new (void);
#endif /* MM_MANAGER_H */

37
src/mm-modem-error.c Normal file
View File

@@ -0,0 +1,37 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "mm-modem-error.h"
GQuark
mm_modem_error_quark (void)
{
static GQuark ret = 0;
if (ret == 0)
ret = g_quark_from_static_string ("mm_modem_error");
return ret;
}
#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
GType
mm_modem_error_get_type (void)
{
static GType etype = 0;
if (etype == 0) {
static const GEnumValue values[] = {
ENUM_ENTRY (MM_MODEM_ERROR_GENERAL, "GeneralError"),
ENUM_ENTRY (MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED, "OperationNotSupported"),
ENUM_ENTRY (MM_MODEM_ERROR_PIN_NEEDED, "PINNeeded"),
ENUM_ENTRY (MM_MODEM_ERROR_PUK_NEEDED, "PUKNeeded"),
ENUM_ENTRY (MM_MODEM_ERROR_INVALID_SECRET, "InvalidSecret"),
{ 0, 0, 0 }
};
etype = g_enum_register_static ("MMModemError", values);
}
return etype;
}

22
src/mm-modem-error.h Normal file
View File

@@ -0,0 +1,22 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef MM_MODEM_ERROR_H
#define MM_MODEM_ERROR_H
#include <glib-object.h>
enum {
MM_MODEM_ERROR_GENERAL = 0,
MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED,
MM_MODEM_ERROR_PIN_NEEDED,
MM_MODEM_ERROR_PUK_NEEDED,
MM_MODEM_ERROR_INVALID_SECRET
};
#define MM_MODEM_ERROR (mm_modem_error_quark ())
#define MM_TYPE_MODEM_ERROR (mm_modem_error_get_type ())
GQuark mm_modem_error_quark (void);
GType mm_modem_error_get_type (void);
#endif /* MM_MODEM_ERROR_H */

460
src/mm-modem.c Normal file
View File

@@ -0,0 +1,460 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include <string.h>
#include <dbus/dbus-glib.h>
#include "mm-modem.h"
#include "mm-modem-error.h"
#include "mm-callback-info.h"
static void impl_modem_enable (MMModem *modem, gboolean enable, DBusGMethodInvocation *context);
static void impl_modem_set_pin (MMModem *modem, const char *pin, DBusGMethodInvocation *context);
static void impl_modem_register (MMModem *modem, const char *network_id, DBusGMethodInvocation *context);
static void impl_modem_connect (MMModem *modem, const char *number, const char *apn, DBusGMethodInvocation *context);
static void impl_modem_disconnect (MMModem *modem, DBusGMethodInvocation *context);
static void impl_modem_scan (MMModem *modem, DBusGMethodInvocation *context);
static void impl_modem_get_signal_quality (MMModem *modem, DBusGMethodInvocation *context);
static void impl_modem_set_band (MMModem *modem, guint32 band, DBusGMethodInvocation *context);
static void impl_modem_get_band (MMModem *modem, DBusGMethodInvocation *context);
static void impl_modem_set_network_mode (MMModem *modem, guint32 mode, DBusGMethodInvocation *context);
static void impl_modem_get_network_mode (MMModem *modem, DBusGMethodInvocation *context);
#include "mm-modem-glue.h"
enum {
SIGNAL_QUALITY,
NETWORK_MODE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
static void
async_op_not_supported (MMModem *self,
MMModemFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
info = mm_callback_info_new (self, callback, user_data);
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED,
"%s", "Operation not supported");
mm_callback_info_schedule (info);
}
static void
async_call_done (MMModem *modem, GError *error, gpointer user_data)
{
DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
if (error)
dbus_g_method_return_error (context, error);
else
dbus_g_method_return (context);
}
static void
uint_op_not_supported (MMModem *self,
MMModemUIntFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
info = mm_callback_info_uint_new (self, callback, user_data);
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED,
"%s", "Operation not supported");
mm_callback_info_schedule (info);
}
static void
uint_call_done (MMModem *modem, guint32 result, GError *error, gpointer user_data)
{
DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
if (error)
dbus_g_method_return_error (context, error);
else
dbus_g_method_return (context, result);
}
void
mm_modem_enable (MMModem *self,
gboolean enable,
MMModemFn callback,
gpointer user_data)
{
g_return_if_fail (MM_IS_MODEM (self));
g_return_if_fail (callback != NULL);
if (MM_MODEM_GET_INTERFACE (self)->enable)
MM_MODEM_GET_INTERFACE (self)->enable (self, enable, callback, user_data);
else
async_op_not_supported (self, callback, user_data);
}
static void
impl_modem_enable (MMModem *modem,
gboolean enable,
DBusGMethodInvocation *context)
{
mm_modem_enable (modem, enable, async_call_done, context);
}
void
mm_modem_set_pin (MMModem *self,
const char *pin,
MMModemFn callback,
gpointer user_data)
{
g_return_if_fail (MM_IS_MODEM (self));
g_return_if_fail (callback != NULL);
g_return_if_fail (pin != NULL);
if (MM_MODEM_GET_INTERFACE (self)->set_pin)
MM_MODEM_GET_INTERFACE (self)->set_pin (self, pin, callback, user_data);
else
async_op_not_supported (self, callback, user_data);
}
static void
impl_modem_set_pin (MMModem *modem,
const char *pin,
DBusGMethodInvocation *context)
{
mm_modem_set_pin (modem, pin, async_call_done, context);
}
void
mm_modem_register (MMModem *self,
const char *network_id,
MMModemFn callback,
gpointer user_data)
{
g_return_if_fail (MM_IS_MODEM (self));
g_return_if_fail (callback != NULL);
if (MM_MODEM_GET_INTERFACE (self)->do_register)
MM_MODEM_GET_INTERFACE (self)->do_register (self, network_id, callback, user_data);
else
async_op_not_supported (self, callback, user_data);
}
static void
impl_modem_register (MMModem *modem,
const char *network_id,
DBusGMethodInvocation *context)
{
const char *id;
/* DBus does not support NULL strings, so the caller should pass an empty string
for manual registration. */
if (strlen (network_id) < 1)
id = NULL;
else
id = network_id;
mm_modem_register (modem, id, async_call_done, context);
}
void
mm_modem_connect (MMModem *self,
const char *number,
const char *apn,
MMModemFn callback,
gpointer user_data)
{
g_return_if_fail (MM_IS_MODEM (self));
g_return_if_fail (callback != NULL);
g_return_if_fail (number != NULL);
if (MM_MODEM_GET_INTERFACE (self)->connect)
MM_MODEM_GET_INTERFACE (self)->connect (self, number, apn, callback, user_data);
else
async_op_not_supported (self, callback, user_data);
}
static void
impl_modem_connect (MMModem *modem,
const char *number,
const char *apn,
DBusGMethodInvocation *context)
{
const char *real_apn;
/* DBus does not support NULL strings, so the caller should pass an empty string
for no APN. */
if (strlen (apn) < 1)
real_apn = NULL;
else
real_apn = apn;
mm_modem_connect (modem, number, real_apn, async_call_done, context);
}
void
mm_modem_disconnect (MMModem *self,
MMModemFn callback,
gpointer user_data)
{
g_return_if_fail (MM_IS_MODEM (self));
g_return_if_fail (callback != NULL);
if (MM_MODEM_GET_INTERFACE (self)->disconnect)
MM_MODEM_GET_INTERFACE (self)->disconnect (self, callback, user_data);
else
async_op_not_supported (self, callback, user_data);
}
static void
impl_modem_disconnect (MMModem *modem,
DBusGMethodInvocation *context)
{
mm_modem_disconnect (modem, async_call_done, context);
}
void
mm_modem_scan (MMModem *self,
MMModemScanFn callback,
gpointer user_data)
{
g_return_if_fail (MM_IS_MODEM (self));
g_return_if_fail (callback != NULL);
if (MM_MODEM_GET_INTERFACE (self)->scan)
MM_MODEM_GET_INTERFACE (self)->scan (self, callback, user_data);
else
/* FIXME */ ;
}
static void
impl_scan_done (MMModem *modem, GPtrArray *results, GError *error, gpointer user_data)
{
DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
if (error)
dbus_g_method_return_error (context, error);
else
dbus_g_method_return (context, results);
}
static void
impl_modem_scan (MMModem *modem,
DBusGMethodInvocation *context)
{
mm_modem_scan (modem, impl_scan_done, context);
}
void
mm_modem_get_signal_quality (MMModem *self,
MMModemUIntFn callback,
gpointer user_data)
{
g_return_if_fail (MM_IS_MODEM (self));
g_return_if_fail (callback != NULL);
if (MM_MODEM_GET_INTERFACE (self)->get_signal_quality)
MM_MODEM_GET_INTERFACE (self)->get_signal_quality (self, callback, user_data);
else
uint_op_not_supported (self, callback, user_data);
}
static void
impl_modem_get_signal_quality (MMModem *modem, DBusGMethodInvocation *context)
{
mm_modem_get_signal_quality (modem, uint_call_done, context);
}
void
mm_modem_set_band (MMModem *self,
MMModemBand band,
MMModemFn callback,
gpointer user_data)
{
g_return_if_fail (MM_IS_MODEM (self));
g_return_if_fail (callback != NULL);
if (MM_MODEM_GET_INTERFACE (self)->set_band)
MM_MODEM_GET_INTERFACE (self)->set_band (self, band, callback, user_data);
else
async_op_not_supported (self, callback, user_data);
}
static void
impl_modem_set_band (MMModem *modem, guint32 band, DBusGMethodInvocation *context)
{
mm_modem_set_band (modem, band, async_call_done, context);
}
void
mm_modem_get_band (MMModem *self,
MMModemUIntFn callback,
gpointer user_data)
{
g_return_if_fail (MM_IS_MODEM (self));
g_return_if_fail (callback != NULL);
if (MM_MODEM_GET_INTERFACE (self)->get_band)
MM_MODEM_GET_INTERFACE (self)->get_band (self, callback, user_data);
else
uint_op_not_supported (self, callback, user_data);
}
static void
impl_modem_get_band (MMModem *modem, DBusGMethodInvocation *context)
{
mm_modem_get_band (modem, uint_call_done, context);
}
void
mm_modem_set_network_mode (MMModem *self,
MMModemNetworkMode mode,
MMModemFn callback,
gpointer user_data)
{
g_return_if_fail (MM_IS_MODEM (self));
g_return_if_fail (callback != NULL);
if (MM_MODEM_GET_INTERFACE (self)->set_network_mode)
MM_MODEM_GET_INTERFACE (self)->set_network_mode (self, mode, callback, user_data);
else
async_op_not_supported (self, callback, user_data);
}
static void
impl_modem_set_network_mode (MMModem *modem, guint32 mode, DBusGMethodInvocation *context)
{
mm_modem_set_network_mode (modem, mode, async_call_done, context);
}
void
mm_modem_get_network_mode (MMModem *self,
MMModemUIntFn callback,
gpointer user_data)
{
g_return_if_fail (MM_IS_MODEM (self));
g_return_if_fail (callback != NULL);
if (MM_MODEM_GET_INTERFACE (self)->get_network_mode)
MM_MODEM_GET_INTERFACE (self)->get_network_mode (self, callback, user_data);
else
uint_op_not_supported (self, callback, user_data);
}
static void
impl_modem_get_network_mode (MMModem *modem, DBusGMethodInvocation *context)
{
mm_modem_get_network_mode (modem, uint_call_done, context);
}
void
mm_modem_install_dbus_info (GType type)
{
dbus_g_object_type_install_info (type, &dbus_glib_mm_modem_object_info);
}
void
mm_modem_signal_quality (MMModem *self,
guint32 quality)
{
g_return_if_fail (MM_IS_MODEM (self));
g_signal_emit (self, signals[SIGNAL_QUALITY], 0, quality);
}
void
mm_modem_network_mode (MMModem *self,
MMModemNetworkMode mode)
{
g_return_if_fail (MM_IS_MODEM (self));
g_signal_emit (self, signals[NETWORK_MODE], 0, mode);
}
/*****************************************************************************/
static void
mm_modem_init (gpointer g_iface)
{
GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
static gboolean initialized = FALSE;
if (initialized)
return;
/* Properties */
g_object_interface_install_property
(g_iface,
g_param_spec_string (MM_MODEM_DATA_DEVICE,
"DataDevice",
"DataDevice",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_interface_install_property
(g_iface,
g_param_spec_string (MM_MODEM_DRIVER,
"Driver",
"Driver",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_interface_install_property
(g_iface,
g_param_spec_uint (MM_MODEM_TYPE,
"Type",
"Type",
0, G_MAXUINT32, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
/* Signals */
signals[SIGNAL_QUALITY] =
g_signal_new ("signal-quality",
iface_type,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (MMModem, signal_quality),
NULL, NULL,
g_cclosure_marshal_VOID__UINT,
G_TYPE_NONE, 1,
G_TYPE_UINT);
signals[NETWORK_MODE] =
g_signal_new ("network-mode",
iface_type,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (MMModem, network_mode),
NULL, NULL,
g_cclosure_marshal_VOID__UINT,
G_TYPE_NONE, 1,
G_TYPE_UINT);
initialized = TRUE;
}
GType
mm_modem_get_type (void)
{
static GType modem_type = 0;
if (!G_UNLIKELY (modem_type)) {
const GTypeInfo modem_info = {
sizeof (MMModem), /* class_size */
mm_modem_init, /* base_init */
NULL, /* base_finalize */
NULL,
NULL, /* class_finalize */
NULL, /* class_data */
0,
0, /* n_preallocs */
NULL
};
modem_type = g_type_register_static (G_TYPE_INTERFACE,
"MMModem",
&modem_info, 0);
g_type_interface_add_prerequisite (modem_type, G_TYPE_OBJECT);
}
return modem_type;
}

196
src/mm-modem.h Normal file
View File

@@ -0,0 +1,196 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef MM_MODEM_H
#define MM_MODEM_H
#include <glib-object.h>
#define MM_TYPE_MODEM (mm_modem_get_type ())
#define MM_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM, MMModem))
#define MM_IS_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM))
#define MM_MODEM_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_MODEM, MMModem))
#define MM_MODEM_DATA_DEVICE "data-device"
#define MM_MODEM_DRIVER "driver"
#define MM_MODEM_TYPE "type"
#define MM_MODEM_TYPE_GSM 1
#define MM_MODEM_TYPE_CDMA 2
typedef enum {
MM_MODEM_PROP_FIRST = 0x1000,
MM_MODEM_PROP_DATA_DEVICE = MM_MODEM_PROP_FIRST,
MM_MODEM_PROP_DRIVER,
MM_MODEM_PROP_TYPE
} MMModemProp;
typedef enum {
MM_MODEM_NETWORK_MODE_ANY = 0,
MM_MODEM_NETWORK_MODE_GPRS = 1,
MM_MODEM_NETWORK_MODE_EDGE = 2,
MM_MODEM_NETWORK_MODE_3G = 3,
MM_MODEM_NETWORK_MODE_HSDPA = 4,
MM_MODEM_NETWORK_MODE_PREFER_2G = 5,
MM_MODEM_NETWORK_MODE_PREFER_3G = 6
} MMModemNetworkMode;
typedef enum {
MM_MODEM_BAND_ANY = 0,
MM_MODEM_BAND_EGSM = 1, /* 900 MHz */
MM_MODEM_BAND_DCS = 2, /* 1800 MHz */
MM_MODEM_BAND_PCS = 3, /* 1900 MHz */
MM_MODEM_BAND_G850 = 4, /* 850 MHz */
MM_MODEM_BAND_U2100 = 5, /* WCDMA 2100 MHz (Class I) */
MM_MODEM_BAND_U1700 = 6, /* WCDMA 3GPP UMTS1800 MHz (Class III) */
MM_MODEM_BAND_17IV = 7, /* WCDMA 3GPP AWS 1700/2100 MHz (Class IV) */
MM_MODEM_BAND_U800 = 8, /* WCDMA 3GPP UMTS800 MHz (Class VI) */
MM_MODEM_BAND_U850 = 9, /* WCDMA 3GPP UMTS850 MHz (Class V) */
MM_MODEM_BAND_U900 = 10, /* WCDMA 3GPP UMTS900 MHz (Class VIII) */
MM_MODEM_BAND_U17IX = 11 /* WCDMA 3GPP UMTS MHz (Class IX) */
} MMModemBand;
typedef struct _MMModem MMModem;
typedef void (*MMModemFn) (MMModem *modem,
GError *error,
gpointer user_data);
typedef void (*MMModemUIntFn) (MMModem *modem,
guint32 result,
GError *error,
gpointer user_data);
typedef void (*MMModemScanFn) (MMModem *modem,
GPtrArray *results,
GError *error,
gpointer user_data);
struct _MMModem {
GTypeInterface g_iface;
/* Methods */
void (*enable) (MMModem *self,
gboolean enable,
MMModemFn callback,
gpointer user_data);
void (*set_pin) (MMModem *self,
const char *pin,
MMModemFn callback,
gpointer user_data);
/* 'register' is a reserved word */
void (*do_register) (MMModem *self,
const char *network_id,
MMModemFn callback,
gpointer user_data);
void (*connect) (MMModem *self,
const char *number,
const char *apn,
MMModemFn callback,
gpointer user_data);
void (*disconnect) (MMModem *self,
MMModemFn callback,
gpointer user_data);
void (*scan) (MMModem *self,
MMModemScanFn callback,
gpointer user_data);
void (*get_signal_quality) (MMModem *self,
MMModemUIntFn callback,
gpointer user_data);
void (*set_band) (MMModem *self,
MMModemBand band,
MMModemFn callback,
gpointer user_data);
void (*get_band) (MMModem *self,
MMModemUIntFn callback,
gpointer user_data);
void (*set_network_mode) (MMModem *self,
MMModemNetworkMode mode,
MMModemFn callback,
gpointer user_data);
void (*get_network_mode) (MMModem *self,
MMModemUIntFn callback,
gpointer user_data);
/* Signals */
void (*signal_quality) (MMModem *self,
guint32 quality);
void (*network_mode) (MMModem *self,
MMModemNetworkMode mode);
};
GType mm_modem_get_type (void);
void mm_modem_enable (MMModem *self,
gboolean enable,
MMModemFn callback,
gpointer user_data);
void mm_modem_set_pin (MMModem *self,
const char *pin,
MMModemFn callback,
gpointer user_data);
void mm_modem_register (MMModem *self,
const char *network_id,
MMModemFn callback,
gpointer user_data);
void mm_modem_connect (MMModem *self,
const char *number,
const char *apn,
MMModemFn callback,
gpointer user_data);
void mm_modem_disconnect (MMModem *self,
MMModemFn callback,
gpointer user_data);
void mm_modem_scan (MMModem *self,
MMModemScanFn callback,
gpointer user_data);
void mm_modem_get_signal_quality (MMModem *self,
MMModemUIntFn callback,
gpointer user_data);
void mm_modem_set_band (MMModem *self,
MMModemBand band,
MMModemFn callback,
gpointer user_data);
void mm_modem_get_band (MMModem *self,
MMModemUIntFn callback,
gpointer user_data);
void mm_modem_set_network_mode (MMModem *self,
MMModemNetworkMode mode,
MMModemFn callback,
gpointer user_data);
void mm_modem_get_network_mode (MMModem *self,
MMModemUIntFn callback,
gpointer user_data);
/* Protected */
void mm_modem_install_dbus_info (GType type);
void mm_modem_signal_quality (MMModem *self,
guint32 quality);
void mm_modem_network_mode (MMModem *self,
MMModemNetworkMode mode);
#endif /* MM_MODEM_H */

81
src/mm-plugin.c Normal file
View File

@@ -0,0 +1,81 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "mm-plugin.h"
const char *
mm_plugin_get_name (MMPlugin *plugin)
{
g_return_val_if_fail (MM_IS_PLUGIN (plugin), NULL);
return MM_PLUGIN_GET_INTERFACE (plugin)->get_name (plugin);
}
char **
mm_plugin_list_supported_udis (MMPlugin *plugin,
LibHalContext *hal_ctx)
{
g_return_val_if_fail (MM_IS_PLUGIN (plugin), NULL);
g_return_val_if_fail (hal_ctx != NULL, NULL);
return MM_PLUGIN_GET_INTERFACE (plugin)->list_supported_udis (plugin, hal_ctx);
}
gboolean
mm_plugin_supports_udi (MMPlugin *plugin,
LibHalContext *hal_ctx,
const char *udi)
{
g_return_val_if_fail (MM_IS_PLUGIN (plugin), FALSE);
g_return_val_if_fail (hal_ctx != NULL, FALSE);
g_return_val_if_fail (udi != NULL, FALSE);
return MM_PLUGIN_GET_INTERFACE (plugin)->supports_udi (plugin, hal_ctx, udi);
}
MMModem *
mm_plugin_create_modem (MMPlugin *plugin,
LibHalContext *hal_ctx,
const char *udi)
{
g_return_val_if_fail (MM_IS_PLUGIN (plugin), NULL);
g_return_val_if_fail (hal_ctx != NULL, NULL);
g_return_val_if_fail (udi != NULL, NULL);
return MM_PLUGIN_GET_INTERFACE (plugin)->create_modem (plugin, hal_ctx, udi);
}
/*****************************************************************************/
static void
mm_plugin_init (gpointer g_iface)
{
}
GType
mm_plugin_get_type (void)
{
static GType plugin_type = 0;
if (!G_UNLIKELY (plugin_type)) {
const GTypeInfo plugin_info = {
sizeof (MMPlugin), /* class_size */
mm_plugin_init, /* base_init */
NULL, /* base_finalize */
NULL,
NULL, /* class_finalize */
NULL, /* class_data */
0,
0, /* n_preallocs */
NULL
};
plugin_type = g_type_register_static (G_TYPE_INTERFACE,
"MMPlugin",
&plugin_info, 0);
g_type_interface_add_prerequisite (plugin_type, G_TYPE_OBJECT);
}
return plugin_type;
}

55
src/mm-plugin.h Normal file
View File

@@ -0,0 +1,55 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef MM_PLUGIN_H
#define MM_PLUGIN_H
#include <glib-object.h>
#include <libhal.h>
#include <mm-modem.h>
#define MM_PLUGIN_MAJOR_VERSION 1
#define MM_PLUGIN_MINOR_VERSION 0
#define MM_TYPE_PLUGIN (mm_plugin_get_type ())
#define MM_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN, MMPlugin))
#define MM_IS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN))
#define MM_PLUGIN_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_PLUGIN, MMPlugin))
typedef struct _MMPlugin MMPlugin;
typedef MMPlugin *(*MMPluginCreateFunc) (void);
struct _MMPlugin {
GTypeInterface g_iface;
/* Methods */
const char *(*get_name) (MMPlugin *self);
char **(*list_supported_udis) (MMPlugin *self,
LibHalContext *hal_ctx);
gboolean (*supports_udi) (MMPlugin *self,
LibHalContext *hal_ctx,
const char *udi);
MMModem *(*create_modem) (MMPlugin *self,
LibHalContext *hal_ctx,
const char *udi);
};
GType mm_plugin_get_type (void);
const char *mm_plugin_get_name (MMPlugin *plugin);
char **mm_plugin_list_supported_udis (MMPlugin *plugin,
LibHalContext *hal_ctx);
gboolean mm_plugin_supports_udi (MMPlugin *plugin,
LibHalContext *hal_ctx,
const char *udi);
MMModem *mm_plugin_create_modem (MMPlugin *plugin,
LibHalContext *hal_ctx,
const char *udi);
#endif /* MM_PLUGIN_H */

1117
src/mm-serial.c Normal file

File diff suppressed because it is too large Load Diff

85
src/mm-serial.h Normal file
View File

@@ -0,0 +1,85 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#ifndef MM_SERIAL_H
#define MM_SERIAL_H
#include <glib/gtypes.h>
#include <glib-object.h>
#define MM_TYPE_SERIAL (mm_serial_get_type ())
#define MM_SERIAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SERIAL, MMSerial))
#define MM_SERIAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SERIAL, MMSerialClass))
#define MM_IS_SERIAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SERIAL))
#define MM_IS_SERIAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SERIAL))
#define MM_SERIAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SERIAL, MMSerialClass))
#define MM_SERIAL_DEVICE "device"
#define MM_SERIAL_BAUD "baud"
#define MM_SERIAL_BITS "bits"
#define MM_SERIAL_PARITY "parity"
#define MM_SERIAL_STOPBITS "stopbits"
#define MM_SERIAL_SEND_DELAY "send-delay"
typedef struct {
GObject parent;
} MMSerial;
typedef struct {
GObjectClass parent;
} MMSerialClass;
GType mm_serial_get_type (void);
typedef void (*MMSerialGetReplyFn) (MMSerial *serial,
const char *reply,
gpointer user_data);
typedef void (*MMSerialWaitForReplyFn) (MMSerial *serial,
int reply_index,
gpointer user_data);
typedef void (*MMSerialWaitQuietFn) (MMSerial *serial,
gboolean timed_out,
gpointer user_data);
typedef void (*MMSerialFlashFn) (MMSerial *serial,
gpointer user_data);
const char *mm_serial_get_device (MMSerial *serial);
gboolean mm_serial_open (MMSerial *self);
void mm_serial_close (MMSerial *self);
gboolean mm_serial_send_command (MMSerial *self,
GByteArray *command);
gboolean mm_serial_send_command_string (MMSerial *self,
const char *str);
guint mm_serial_get_reply (MMSerial *self,
guint timeout,
const char *terminators,
MMSerialGetReplyFn callback,
gpointer user_data);
guint mm_serial_wait_for_reply (MMSerial *self,
guint timeout,
char **responses,
char **terminators,
MMSerialWaitForReplyFn callback,
gpointer user_data);
void mm_serial_wait_quiet (MMSerial *self,
guint timeout,
guint quiet_time,
MMSerialWaitQuietFn callback,
gpointer user_data);
guint mm_serial_flash (MMSerial *self,
guint32 flash_time,
MMSerialFlashFn callback,
gpointer user_data);
GIOChannel *mm_serial_get_io_channel (MMSerial *self);
#endif /* MM_SERIAL_H */