aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuido Günther <agx@sigxcpu.org>2014-02-05 08:38:23 +0100
committerGuido Günther <agx@sigxcpu.org>2014-02-05 08:38:23 +0100
commit7fbee6ce27176bfc7ae9b34a4de9452cf5f6fa43 (patch)
tree5cabb0ab457846912d99ef675160be0dce4fbe6f
parentdc645b92b9a7db3076ae34986ac219d01677d124 (diff)
Imported Upstream version 0.4+git.20110124t203624.00b6cceupstream/0.4+git.20110124t203624.00b6cce
-rw-r--r--.gitignore2
-rw-r--r--Makefile.am21
-rw-r--r--NEWS25
-rw-r--r--configure.ac25
-rw-r--r--header-generator.xsl241
-rw-r--r--introspection/Makefile.am25
-rw-r--r--introspection/all.xml28
-rw-r--r--introspection/mm-modem-cdma.xml97
-rw-r--r--introspection/org.freedesktop.DBus.Properties.xml45
-rw-r--r--introspection/org.freedesktop.ModemManager.Modem.Cdma.xml220
-rw-r--r--introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml (renamed from introspection/mm-modem-gsm-card.xml)8
-rw-r--r--introspection/org.freedesktop.ModemManager.Modem.Gsm.Contacts.xml (renamed from introspection/mm-modem-gsm-contacts.xml)0
-rw-r--r--introspection/org.freedesktop.ModemManager.Modem.Gsm.Hso.xml (renamed from introspection/mm-modem-gsm-hso.xml)0
-rw-r--r--introspection/org.freedesktop.ModemManager.Modem.Gsm.Network.xml (renamed from introspection/mm-modem-gsm-network.xml)0
-rw-r--r--introspection/org.freedesktop.ModemManager.Modem.Gsm.SMS.xml (renamed from introspection/mm-modem-gsm-sms.xml)0
-rw-r--r--introspection/org.freedesktop.ModemManager.Modem.Gsm.Ussd.xml (renamed from introspection/mm-modem-gsm-ussd.xml)6
-rw-r--r--introspection/org.freedesktop.ModemManager.Modem.Gsm.xml (renamed from introspection/mm-modem-gsm.xml)3
-rw-r--r--introspection/org.freedesktop.ModemManager.Modem.Location.xml (renamed from introspection/mm-modem-location.xml)2
-rw-r--r--introspection/org.freedesktop.ModemManager.Modem.Simple.xml (renamed from introspection/mm-modem-simple.xml)0
-rw-r--r--introspection/org.freedesktop.ModemManager.Modem.xml (renamed from introspection/mm-modem.xml)92
-rw-r--r--introspection/org.freedesktop.ModemManager.xml (renamed from introspection/mm-manager.xml)0
-rw-r--r--libqcdm/src/Makefile.am3
-rw-r--r--libqcdm/src/commands.c285
-rw-r--r--libqcdm/src/commands.h111
-rw-r--r--libqcdm/src/dm-commands.h68
-rw-r--r--libqcdm/src/error.c1
-rw-r--r--libqcdm/src/error.h1
-rw-r--r--libqcdm/src/libqcdm.ver6
-rw-r--r--libqcdm/src/nv-items.h29
-rw-r--r--libqcdm/tests/test-qcdm-com.c281
-rw-r--r--libqcdm/tests/test-qcdm-com.h8
-rw-r--r--libqcdm/tests/test-qcdm-utils.c20
-rw-r--r--libqcdm/tests/test-qcdm-utils.h2
-rw-r--r--libqcdm/tests/test-qcdm.c9
-rw-r--r--marshallers/Makefile.am4
-rw-r--r--marshallers/mm-marshal.list1
-rw-r--r--plugins/77-mm-ericsson-mbm.rules33
-rw-r--r--plugins/77-mm-x22x-port-types.rules30
-rw-r--r--plugins/77-mm-zte-port-types.rules57
-rw-r--r--plugins/Makefile.am71
-rw-r--r--plugins/mm-modem-anydata-cdma.c34
-rw-r--r--plugins/mm-modem-anydata-cdma.h4
-rw-r--r--plugins/mm-modem-gobi-gsm.c6
-rw-r--r--plugins/mm-modem-gobi-gsm.h4
-rw-r--r--plugins/mm-modem-hso.c8
-rw-r--r--plugins/mm-modem-hso.h4
-rw-r--r--plugins/mm-modem-huawei-cdma.c13
-rw-r--r--plugins/mm-modem-huawei-cdma.h4
-rw-r--r--plugins/mm-modem-huawei-gsm.c88
-rw-r--r--plugins/mm-modem-huawei-gsm.h4
-rw-r--r--plugins/mm-modem-icera.c794
-rw-r--r--plugins/mm-modem-icera.h89
-rw-r--r--plugins/mm-modem-linktop.c208
-rw-r--r--plugins/mm-modem-linktop.h45
-rw-r--r--plugins/mm-modem-longcheer-gsm.c6
-rw-r--r--plugins/mm-modem-longcheer-gsm.h4
-rw-r--r--plugins/mm-modem-mbm.c79
-rw-r--r--plugins/mm-modem-mbm.h4
-rw-r--r--plugins/mm-modem-moto-c-gsm.c6
-rw-r--r--plugins/mm-modem-moto-c-gsm.h4
-rw-r--r--plugins/mm-modem-nokia.c10
-rw-r--r--plugins/mm-modem-nokia.h4
-rw-r--r--plugins/mm-modem-novatel-cdma.c148
-rw-r--r--plugins/mm-modem-novatel-cdma.h4
-rw-r--r--plugins/mm-modem-novatel-gsm.c6
-rw-r--r--plugins/mm-modem-novatel-gsm.h4
-rw-r--r--plugins/mm-modem-option.c6
-rw-r--r--plugins/mm-modem-option.h4
-rw-r--r--plugins/mm-modem-sierra-cdma.c6
-rw-r--r--plugins/mm-modem-sierra-cdma.h4
-rw-r--r--plugins/mm-modem-sierra-gsm.c318
-rw-r--r--plugins/mm-modem-sierra-gsm.h4
-rw-r--r--plugins/mm-modem-simtech-gsm.c6
-rw-r--r--plugins/mm-modem-simtech-gsm.h4
-rw-r--r--plugins/mm-modem-x22x-gsm.c209
-rw-r--r--plugins/mm-modem-x22x-gsm.h45
-rw-r--r--plugins/mm-modem-zte.c206
-rw-r--r--plugins/mm-modem-zte.h4
-rw-r--r--plugins/mm-plugin-anydata.c10
-rw-r--r--plugins/mm-plugin-generic.c33
-rw-r--r--plugins/mm-plugin-gobi.c14
-rw-r--r--plugins/mm-plugin-hso.c10
-rw-r--r--plugins/mm-plugin-huawei.c29
-rw-r--r--plugins/mm-plugin-linktop.c164
-rw-r--r--plugins/mm-plugin-linktop.h41
-rw-r--r--plugins/mm-plugin-longcheer.c14
-rw-r--r--plugins/mm-plugin-mbm.c12
-rw-r--r--plugins/mm-plugin-moto-c.c10
-rw-r--r--plugins/mm-plugin-nokia.c14
-rw-r--r--plugins/mm-plugin-novatel.c14
-rw-r--r--plugins/mm-plugin-option.c10
-rw-r--r--plugins/mm-plugin-sierra.c50
-rw-r--r--plugins/mm-plugin-simtech.c14
-rw-r--r--plugins/mm-plugin-x22x.c192
-rw-r--r--plugins/mm-plugin-x22x.h41
-rw-r--r--plugins/mm-plugin-zte.c35
-rw-r--r--policy/org.freedesktop.modem-manager.policy.in9
-rw-r--r--src/77-mm-usb-device-blacklist.rules6
-rw-r--r--src/80-mm-candidate.rules16
-rw-r--r--src/Makefile.am92
-rw-r--r--src/main.c132
-rw-r--r--src/mm-at-serial-port.c12
-rw-r--r--src/mm-auth-provider-polkit.c27
-rw-r--r--src/mm-auth-provider.h1
-rw-r--r--src/mm-charsets.c353
-rw-r--r--src/mm-charsets.h16
-rw-r--r--src/mm-generic-cdma.c285
-rw-r--r--src/mm-generic-cdma.h8
-rw-r--r--src/mm-generic-gsm.c1310
-rw-r--r--src/mm-generic-gsm.h31
-rw-r--r--src/mm-log.c233
-rw-r--r--src/mm-log.h61
-rw-r--r--src/mm-manager.c119
-rw-r--r--src/mm-modem-base.c201
-rw-r--r--src/mm-modem-cdma.c44
-rw-r--r--src/mm-modem-cdma.h26
-rw-r--r--src/mm-modem-gsm-card.c8
-rw-r--r--src/mm-modem-gsm-card.h1
-rw-r--r--src/mm-modem-gsm-network.c2
-rw-r--r--src/mm-modem-gsm-ussd.c378
-rw-r--r--src/mm-modem-gsm-ussd.h75
-rw-r--r--src/mm-modem-gsm.h3
-rw-r--r--src/mm-modem-helpers.c296
-rw-r--r--src/mm-modem-helpers.h18
-rw-r--r--src/mm-modem-location.c5
-rw-r--r--src/mm-modem-location.h7
-rw-r--r--src/mm-modem.c99
-rw-r--r--src/mm-modem.h22
-rw-r--r--src/mm-options.c55
-rw-r--r--src/mm-options.h23
-rw-r--r--src/mm-plugin-base.c91
-rw-r--r--src/mm-port.c30
-rw-r--r--src/mm-port.h2
-rw-r--r--src/mm-properties-changed-signal.c150
-rw-r--r--src/mm-properties-changed-signal.h18
-rw-r--r--src/mm-qcdm-serial-port.c134
-rw-r--r--src/mm-qcdm-serial-port.h2
-rw-r--r--src/mm-serial-parsers.c28
-rw-r--r--src/mm-serial-port.c87
-rw-r--r--src/mm-serial-port.h1
-rw-r--r--src/mm-utils.c14
-rw-r--r--src/mm-utils.h2
-rw-r--r--src/tests/Makefile.am31
-rw-r--r--src/tests/test-charsets.c323
-rw-r--r--src/tests/test-modem-helpers.c412
-rw-r--r--src/tests/test-qcdm-serial-port.c482
-rw-r--r--test/Makefile.am8
-rwxr-xr-xtest/disable.py27
-rwxr-xr-xtest/enable.py27
-rwxr-xr-xtest/info.py256
-rwxr-xr-xtest/list-modems.py54
-rwxr-xr-xtest/location.py57
-rwxr-xr-xtest/scan.py101
-rwxr-xr-xtest/ussd.py44
154 files changed, 10251 insertions, 1071 deletions
diff --git a/.gitignore b/.gitignore
index dd0a8bb..d8a6a13 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,6 +31,8 @@ docs/spec.html
callouts/mm-modem-probe
test/lsudev
src/tests/test-modem-helpers
+src/tests/test-charsets
+src/tests/test-qcdm-serial-port
policy/org.freedesktop.modem-manager.policy
libqcdm/tests/test-qcdm
diff --git a/Makefile.am b/Makefile.am
index 276a276..4132bc9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,10 +1,11 @@
+XSLTPROC = xsltproc --xinclude --nonet
+
+XMLS = $(wildcard introspection/*.xml)
+
if WITH_DOCS
all:
-XSLTPROC = xsltproc --xinclude --nonet
-
-XMLS = $(wildcard introspection/mm-*.xml)
# Figure out if we need ASYNC_INTROSPECT and add it later
GENERATED_FILES = \
@@ -42,16 +43,27 @@ dbusactivationdir = $(datadir)/dbus-1/system-services
dbusactivation_in_files = org.freedesktop.ModemManager.service.in
dbusactivation_DATA = $(dbusactivation_in_files:.service.in=.service)
+includedir = @includedir@/mm
+
+include_HEADERS = include/mm-modem.h
+
+include/mm-modem.h: $(XMLS) introspection/all.xml header-generator.xsl
+ @install -d include
+ $(XSLTPROC) header-generator.xsl introspection/all.xml > $@
+
%service: %service.in
$(edit) $< >$@
+xmldir = $(datadir)/dbus-1/interfaces
+xml_DATA = $(XMLS)
+
edit = @sed \
-e 's|@sbindir[@]|$(sbindir)|g' \
-e 's|@sysconfdir[@]|$(sysconfdir)|g' \
-e 's|@localstatedir[@]|$(localstatedir)|g' \
-e 's|@libexecdir[@]|$(libexecdir)|g'
-DISTCHECK_CONFIGURE_FLAGS = --with-udev-base-dir=$dc_install_base
+DISTCHECK_CONFIGURE_FLAGS = --with-udev-base-dir=$dc_install_base --with-tests=yes
INTLTOOL_FILES = \
intltool-extract.in \
@@ -68,6 +80,7 @@ DISTCLEANFILES = \
EXTRA_DIST = \
doc-generator.xsl \
+ header-generator.xsl \
$(dbusactivation_in_files) \
$(INTLTOOL_FILES) \
$(dbusservice_file_polkit) \
diff --git a/NEWS b/NEWS
index e69de29..45c2da3 100644
--- a/NEWS
+++ b/NEWS
@@ -0,0 +1,25 @@
+Overview of changes in ModemManager 0.5
+----------------------------------------
+
+- Added a mechanism to get remaining incorrect PIN attempts
+- Added a mechanism to retrieve the equipment identifier (MEID/ESN, IMEI)
+- Added support for returning devices to factory settings
+- Better compatibility with Blackberry GSM devices
+- Added a Location Services API with support for GSM devices
+- Fixes for Novatel CDMA devices (home/roaming status, better signal quality reporting)
+- Better detection of EVDO registration when device is in 1X mode
+- Add support for newer Alcatel devices like X220D
+- Support for more ZTE devices
+- Fix modem detection failures with some Sierra devices
+- Add support for newer Ericsson devices
+- Add an SIM identifier for use when auto-unlocking modems
+- Add an device identifier for use when MEID/IMEI is not yet available
+- Handle signal quality reporting for GSM modems that don't support AT+CSQ
+- Add preliminary USSD support
+- Fix reconnection attempts with some Sierra devices
+- Add support for pseduo-ethernet interface on newer Sierra devices
+
+Fixed bugs:
+rh#597296 rh#583691 rh#597088 bgo#626421 rh#585394 bgo#628105 bgo#627935
+bgo#621815 rh#632516 lp:682282 bgo#590798
+
diff --git a/configure.ac b/configure.ac
index b763d7b..4f8b94f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,6 +2,7 @@ AC_PREREQ(2.52)
AC_INIT(ModemManager, 0.4, dcbw@redhat.com, ModemManager)
AM_INIT_AUTOMAKE([1.9 subdir-objects tar-ustar no-dist-gzip dist-bzip2])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AM_MAINTAINER_MODE
AC_CONFIG_MACRO_DIR([m4])
@@ -26,7 +27,7 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package])
IT_PROG_INTLTOOL([0.35.0])
AM_GLIB_GNU_GETTEXT
-PKG_CHECK_MODULES(MM, dbus-glib-1 >= 0.75 glib-2.0 >= 2.18 gmodule-2.0 gobject-2.0)
+PKG_CHECK_MODULES(MM, dbus-glib-1 >= 0.86 glib-2.0 >= 2.18 gmodule-2.0 gobject-2.0)
PKG_CHECK_MODULES(GUDEV, gudev-1.0)
AC_SUBST(GUDEV_CFLAGS)
@@ -63,12 +64,22 @@ case $with_polkit in
AC_DEFINE(WITH_POLKIT, 1, [Define if you want to use PolicyKit])
AC_SUBST(POLKIT_CFLAGS)
AC_SUBST(POLKIT_LIBS)
+
+ # Check for polkit_authority_get_sync()
+ AC_CHECK_LIB([polkit-gobject-1], [polkit_authority_get_sync], ac_have_pk_auth_get_sync="1", ac_have_pk_auth_get_sync="0")
+ AC_DEFINE_UNQUOTED(HAVE_POLKIT_AUTHORITY_GET_SYNC, $ac_have_pk_auth_get_sync, [Define if you have a polkit with polkit_authority_get_sync()])
;;
*)
with_polkit=no
;;
esac
+dnl
+dnl Checks for new dbus-glib property access function
+dnl
+AC_CHECK_LIB([dbus-glib-1], [dbus_glib_global_set_disable_legacy_property_access], ac_have_dg_prop="1", ac_have_dg_prop="0")
+AC_DEFINE_UNQUOTED(HAVE_DBUS_GLIB_DISABLE_LEGACY_PROP_ACCESS, $ac_have_dg_prop, [Define if you have a dbus-glib with dbus_glib_global_set_disable_legacy_property_access()])
+
# PPPD
AC_CHECK_HEADERS(pppd/pppd.h, have_pppd_headers="yes", have_pppd_headers="no")
AM_CONDITIONAL(HAVE_PPPD_H, test "x$have_pppd_headers" = "xyes")
@@ -115,18 +126,6 @@ NM_COMPILER_WARNINGS
dnl
-dnl dbus-glib >= 0.86 is required for Location API support
-dnl
-with_location_api=no
-PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1 >= 0.86, with_location_api="yes", with_location_api="no")
-if test x"$with_location_api" = xyes; then
- AC_DEFINE(LOCATION_API, 1, [Define if you have dbus-glib 0.86 or higher])
-else
- AC_MSG_WARN([dbus-glib >= 0.86 is required for Location API support])
-fi
-AM_CONDITIONAL(WITH_LOCATION_API, test "x$with_location_api" = "xyes")
-
-dnl
dnl Distribution version string
dnl
AC_ARG_WITH(dist-version, AS_HELP_STRING([--with-dist-version=<mm-dist-version>], [Define the custom version (like distribution package name and revision)]), ac_distver=$withval, ac_distver="")
diff --git a/header-generator.xsl b/header-generator.xsl
new file mode 100644
index 0000000..67f915f
--- /dev/null
+++ b/header-generator.xsl
@@ -0,0 +1,241 @@
+<!-- Generate a C header file from the Modem Manager specification.
+
+Copyright (C) 2006, 2007 Collabora Limited
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+-->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+ exclude-result-prefixes="tp">
+ <!--Don't move the declaration of the HTML namespace up here - XMLNSs
+ don't work ideally in the presence of two things that want to use the
+ absence of a prefix, sadly. -->
+
+ <xsl:strip-space elements="node interface property tp:errors tp:mapping
+ tp:member"/>
+ <xsl:template match="*" mode="identity">
+ <xsl:copy>
+ <xsl:apply-templates mode="identity"/>
+ </xsl:copy>
+ </xsl:template>
+ <xsl:template match="tp:docstring">
+ </xsl:template>
+ <xsl:template match="tp:realdocstring">
+/* <xsl:apply-templates select="node()" mode="identity"/> */
+ </xsl:template>
+ <xsl:template match="tp:errors">
+ <xsl:apply-templates/>
+ </xsl:template>
+ <xsl:template match="tp:generic-types">
+ <xsl:call-template name="do-types"/>
+ </xsl:template>
+ <xsl:template name="do-types">
+ <xsl:if test="tp:simple-type">
+ <xsl:apply-templates select="tp:simple-type"/>
+ </xsl:if>
+ <xsl:if test="tp:enum">
+ <xsl:apply-templates select="tp:enum"/>
+ </xsl:if>
+ <xsl:if test="tp:flags">
+ <xsl:apply-templates select="tp:flags"/>
+ </xsl:if>
+ </xsl:template>
+ <xsl:template match="tp:error">
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:variable name="nameprefix">
+ <xsl:value-of select="translate(substring-after(../@namespace, 'org.freedesktop.ModemManager.'),
+ 'abcdefghijklmnopqrstuvwxyz. ',
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_')"/>
+ </xsl:variable>
+ <xsl:variable name="name">
+ <xsl:value-of select="translate(@name,
+ 'abcdefghijklmnopqrstuvwxyz. ',
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ__')"/>
+ </xsl:variable>
+#define <xsl:value-of select="concat('MM_ERROR_', $nameprefix, '_', $name)"/> "<xsl:value-of select="translate(@name, ' ', '')"/>"</xsl:template>
+
+ <xsl:template match="tp:flags">
+/* <xsl:value-of select="@name"/> flag values */
+<xsl:apply-templates select="tp:docstring" />
+ <xsl:variable name="value-prefix">
+ <xsl:choose>
+ <xsl:when test="@value-prefix">
+ <xsl:value-of select="@value-prefix"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@name"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:for-each select="tp:flag">
+ <xsl:choose>
+ <xsl:when test="tp:docstring">
+ <xsl:apply-templates select="tp:docstring"/>
+ </xsl:when>
+ </xsl:choose>
+#define <xsl:value-of select="concat($value-prefix, '_', @suffix)"/><xsl:text> </xsl:text><xsl:value-of select="@value"/>
+ </xsl:for-each><xsl:text>
+</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="tp:enum">
+/* <xsl:value-of select="@name"/> enum values */
+<xsl:apply-templates select="tp:docstring" />
+ <xsl:variable name="value-prefix">
+ <xsl:choose>
+ <xsl:when test="@value-prefix">
+ <xsl:value-of select="@value-prefix"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@name"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:for-each select="tp:enumvalue">
+ <xsl:choose>
+ <xsl:when test="tp:docstring">
+ <xsl:apply-templates select="tp:docstring" />
+ </xsl:when>
+ </xsl:choose>
+#define <xsl:value-of select="concat($value-prefix, '_', @suffix, ' ')"/><xsl:value-of select="@value"/>
+ </xsl:for-each><xsl:text>
+</xsl:text>
+ </xsl:template>
+
+ <xsl:template match="tp:possible-errors/tp:error">
+ <xsl:variable name="name" select="@name"/>
+ <xsl:choose>
+ <xsl:when test="tp:docstring">
+ <xsl:apply-templates select="tp:docstring"/>
+ </xsl:when>
+ <xsl:when test="//tp:errors/tp:error[concat(../@namespace, '.', translate(@name, ' ', ''))=$name]/tp:docstring">
+ <xsl:apply-templates select="//tp:errors/tp:error[concat(../@namespace, '.', translate(@name, ' ', ''))=$name]/tp:docstring"/> <em xmlns="http://www.w3.org/1999/xhtml">(generic description)</em>
+ </xsl:when>
+ <xsl:otherwise>
+ (Undocumented.)
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="signal">
+ <xsl:variable name="varname">
+ <xsl:value-of select="translate(@name,
+ 'abcdefghijklmnopqrstuvwxyz. ',
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_')"/>
+ </xsl:variable>
+ <xsl:variable name="intname">
+ <xsl:choose>
+ <xsl:when test="starts-with(../@name, 'org.freedesktop.ModemManager.')">
+ <xsl:value-of select="translate(substring-after(../@name, 'org.freedesktop.ModemManager.'),
+ 'abcdefghijklmnopqrstuvwxyz. ',
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>MANAGER</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+#define <xsl:value-of select="concat('MM_', $intname, '_SIGNAL_', $varname)"/> "<xsl:value-of select="@name"/>"</xsl:template>
+
+ <xsl:template match="method">
+ <xsl:variable name="varname">
+ <xsl:value-of select="translate(@name,
+ 'abcdefghijklmnopqrstuvwxyz. ',
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_')"/>
+ </xsl:variable>
+ <xsl:variable name="intname">
+ <xsl:choose>
+ <xsl:when test="starts-with(../@name, 'org.freedesktop.ModemManager.')">
+ <xsl:value-of select="translate(substring-after(../@name, 'org.freedesktop.ModemManager.'),
+ 'abcdefghijklmnopqrstuvwxyz. ',
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>MANAGER</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+#define <xsl:value-of select="concat('MM_', $intname, '_METHOD_', $varname)"/> "<xsl:value-of select="@name"/>"</xsl:template>
+
+ <xsl:template match="tp:copyright">
+ </xsl:template>
+
+ <xsl:output method="text" indent="no" encoding="ascii"
+ omit-xml-declaration="yes" />
+
+ <xsl:template match="/tp:spec">
+/* Generated Header file do not edit */
+/* <xsl:value-of select="tp:title"/> */
+<xsl:if test="tp:version">
+/*
+ * <xsl:text> version </xsl:text> <xsl:value-of select="tp:version"/>
+ */
+</xsl:if>
+#define MM_MODEMMANAGER_PATH "/org/freedesktop/ModemManager"
+#define MM_MODEMMANAGER_SERVICE "org.freedesktop.ModemManager"
+
+/**************
+ * Interfaces *
+ **************/
+<xsl:for-each select="node/interface">
+ <xsl:apply-templates select="tp:docstring"/>
+ <xsl:variable name="varname">
+ <xsl:choose>
+ <xsl:when test="starts-with(@name, 'org.freedesktop.ModemManager.')">
+ <xsl:value-of select="translate(substring-after(@name, 'org.freedesktop.ModemManager.'),
+ 'abcdefghijklmnopqrstuvwxyz. ',
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_')"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="translate(substring-after(@name, 'org.freedesktop.'),
+ 'abcdefghijklmnopqrstuvwxyz. ',
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_')"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+#define <xsl:value-of select="concat('MM_', $varname, '_INTERFACE ')"/> "<xsl:value-of select="@name"/>"</xsl:for-each>
+
+/***********************
+ * Methods/Enums/Flags *
+ ***********************/
+<xsl:for-each select="node/interface">
+/*
+ * Interface <xsl:value-of select="@name"/>
+ */
+ <xsl:apply-templates select="method"/>
+ <xsl:if test="count(method[*])!=0">
+ <xsl:text>
+</xsl:text>
+ </xsl:if>
+ <xsl:apply-templates select="signal"/>
+ <xsl:if test="count(signal[*])!=0">
+ <xsl:text>
+</xsl:text>
+ </xsl:if>
+ <xsl:apply-templates select="tp:enum"/>
+ <xsl:apply-templates select="tp:flags"/>
+</xsl:for-each>
+/**********
+ * Errors *
+ **********/
+<xsl:apply-templates select="tp:errors"/>
+
+<!-- Ensure that the file ends with a newline -->
+<xsl:text>
+</xsl:text>
+</xsl:template>
+</xsl:stylesheet>
+
+<!-- vim:set sw=2 sts=2 et: -->
diff --git a/introspection/Makefile.am b/introspection/Makefile.am
index 941c924..3c7a380 100644
--- a/introspection/Makefile.am
+++ b/introspection/Makefile.am
@@ -1,18 +1,19 @@
EXTRA_DIST = \
all.xml \
- mm-manager.xml \
+ org.freedesktop.ModemManager.xml \
mm-mobile-error.xml \
- mm-modem.xml \
- mm-modem-cdma.xml \
+ org.freedesktop.ModemManager.Modem.xml \
+ org.freedesktop.ModemManager.Modem.Cdma.xml \
mm-modem-connect-error.xml \
mm-modem-error.xml \
- mm-modem-gsm.xml \
- mm-modem-gsm-card.xml \
- mm-modem-gsm-contacts.xml \
- mm-modem-gsm-hso.xml \
- mm-modem-gsm-network.xml \
- mm-modem-gsm-sms.xml \
- mm-modem-simple.xml \
+ org.freedesktop.ModemManager.Modem.Gsm.xml \
+ org.freedesktop.ModemManager.Modem.Gsm.Card.xml \
+ org.freedesktop.ModemManager.Modem.Gsm.Contacts.xml \
+ org.freedesktop.ModemManager.Modem.Gsm.Hso.xml \
+ org.freedesktop.ModemManager.Modem.Gsm.Network.xml \
+ org.freedesktop.ModemManager.Modem.Gsm.SMS.xml \
+ org.freedesktop.ModemManager.Modem.Simple.xml \
mm-serial-error.xml \
- mm-modem-location.xml \
- mm-modem-gsm-ussd.xml
+ org.freedesktop.ModemManager.Modem.Location.xml \
+ org.freedesktop.ModemManager.Modem.Gsm.Ussd.xml \
+ org.freedesktop.DBus.Properties.xml
diff --git a/introspection/all.xml b/introspection/all.xml
index 967e90d..ff174d8 100644
--- a/introspection/all.xml
+++ b/introspection/all.xml
@@ -3,8 +3,9 @@
xmlns:xi="http://www.w3.org/2001/XInclude">
<tp:title>ModemManager D-Bus Interface Specification</tp:title>
- <tp:version>0.1</tp:version>
+ <tp:version>0.5</tp:version>
<tp:copyright>Copyright (C) 2008 Novell, Inc.</tp:copyright>
+ <tp:copyright>Copyright (C) 2008 - 2010 Red Hat, Inc.</tp:copyright>
<tp:license xmlns="http://www.w3.org/1999/xhtml">
<p>This program is free software; you can redistribute it and/or modify
@@ -22,18 +23,19 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</p>
</tp:license>
- <xi:include href="mm-manager.xml"/>
- <xi:include href="mm-modem.xml"/>
- <xi:include href="mm-modem-simple.xml"/>
- <xi:include href="mm-modem-location.xml"/>
- <xi:include href="mm-modem-cdma.xml"/>
- <xi:include href="mm-modem-gsm.xml"/>
- <xi:include href="mm-modem-gsm-card.xml"/>
- <xi:include href="mm-modem-gsm-contacts.xml"/>
- <xi:include href="mm-modem-gsm-network.xml"/>
- <xi:include href="mm-modem-gsm-sms.xml"/>
- <xi:include href="mm-modem-gsm-hso.xml"/>
- <xi:include href="mm-modem-gsm-ussd.xml"/>
+ <xi:include href="org.freedesktop.ModemManager.xml"/>
+ <xi:include href="org.freedesktop.ModemManager.Modem.xml"/>
+ <xi:include href="org.freedesktop.ModemManager.Modem.Simple.xml"/>
+ <xi:include href="org.freedesktop.ModemManager.Modem.Location.xml"/>
+ <xi:include href="org.freedesktop.ModemManager.Modem.Cdma.xml"/>
+ <xi:include href="org.freedesktop.ModemManager.Modem.Gsm.xml"/>
+ <xi:include href="org.freedesktop.ModemManager.Modem.Gsm.Card.xml"/>
+ <xi:include href="org.freedesktop.ModemManager.Modem.Gsm.Contacts.xml"/>
+ <xi:include href="org.freedesktop.ModemManager.Modem.Gsm.Network.xml"/>
+ <xi:include href="org.freedesktop.ModemManager.Modem.Gsm.SMS.xml"/>
+ <xi:include href="org.freedesktop.ModemManager.Modem.Gsm.Hso.xml"/>
+ <xi:include href="org.freedesktop.ModemManager.Modem.Gsm.Ussd.xml"/>
+ <xi:include href="org.freedesktop.DBus.Properties.xml"/>
<xi:include href="mm-serial-error.xml"/>
<xi:include href="mm-modem-error.xml"/>
diff --git a/introspection/mm-modem-cdma.xml b/introspection/mm-modem-cdma.xml
deleted file mode 100644
index e224296..0000000
--- a/introspection/mm-modem-cdma.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
- <interface name="org.freedesktop.ModemManager.Modem.Cdma">
-
- <method name="GetSignalQuality">
- <tp:docstring>
- Get the current signal quality.
- </tp:docstring>
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_cdma_get_signal_quality"/>
- <arg name="quality" type="u" direction="out">
- <tp:docstring>
- Signal quality (percent).
- </tp:docstring>
- </arg>
- </method>
-
- <method name="GetEsn">
- <tp:docstring>
- Get the Electronic Serial Number of the card.
- </tp:docstring>
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_cdma_get_esn"/>
- <arg name="esn" type="s" direction="out">
- <tp:docstring>
- The ESN.
- </tp:docstring>
- </arg>
- </method>
-
- <method name="GetServingSystem">
- <tp:docstring>
- Get the Service System details of the current network, if registered.
- </tp:docstring>
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_cdma_get_serving_system"/>
- <arg name="info" type="(usu)" direction="out">
- <tp:docstring>
- A structure containing the Band Class (0 = unknown, 1 = 800 MHz, 2 = 1900 MHz), the Band ("A" - "F" as defined by IS707-A), and the System ID of the serving network.
- </tp:docstring>
- </arg>
- </method>
-
- <signal name="SignalQuality">
- <tp:docstring>
- The signal quality changed.
- </tp:docstring>
- <arg name="quality" type="u">
- <tp:docstring>
- The new quality in percent, 0..100.
- </tp:docstring>
- </arg>
- </signal>
-
- <method name="GetRegistrationState">
- <tp:docstring>Get device registration state.</tp:docstring>
- <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
- <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_cdma_get_registration_state"/>
- <arg name="cdma-1x-state" type="u" direction="out" tp:type="MM_MODEM_CDMA_REGISTRATION_STATE">
- <tp:docstring>CDMA 1x registration state.</tp:docstring>
- </arg>
- <arg name="evdo-state" type="u" direction="out" tp:type="MM_MODEM_CDMA_REGISTRATION_STATE">
- <tp:docstring>EVDO registration state.</tp:docstring>
- </arg>
- </method>
-
- <signal name="RegistrationStateChanged">
- <tp:docstring>
- The device registration state changed.
- </tp:docstring>
- <arg name="cdma-1x-state" type="u" tp:type="MM_MODEM_CDMA_REGISTRATION_STATE">
- <tp:docstring>CDMA 1x registration state.</tp:docstring>
- </arg>
- <arg name="evdo-state" type="u" tp:type="MM_MODEM_CDMA_REGISTRATION_STATE">
- <tp:docstring>EVDO registration state.</tp:docstring>
- </arg>
- </signal>
-
- <tp:enum name="MM_MODEM_CDMA_REGISTRATION_STATE" type="u">
- <tp:enumvalue suffix="UNKNOWN" value="0">
- <tp:docstring>Registration status is unknown or the device is not registered.</tp:docstring>
- </tp:enumvalue>
- <tp:enumvalue suffix="REGISTERED" value="1">
- <tp:docstring>Registered, but roaming status is unknown or cannot be provided by the device. The device may or may not be roaming.</tp:docstring>
- </tp:enumvalue>
- <tp:enumvalue suffix="HOME" value="2">
- <tp:docstring>Currently registered on the home network.</tp:docstring>
- </tp:enumvalue>
- <tp:enumvalue suffix="ROAMING" value="3">
- <tp:docstring>Currently registered on a roaming network.</tp:docstring>
- </tp:enumvalue>
- </tp:enum>
-
- </interface>
-</node>
-
diff --git a/introspection/org.freedesktop.DBus.Properties.xml b/introspection/org.freedesktop.DBus.Properties.xml
new file mode 100644
index 0000000..b2d0923
--- /dev/null
+++ b/introspection/org.freedesktop.DBus.Properties.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
+ <interface name="org.freedesktop.DBus.Properties">
+ <signal name="MmPropertiesChanged">
+ <tp:docstring>
+ One or more properties' values changed.
+ </tp:docstring>
+ <arg name="interface" type="s">
+ <tp:docstring>
+ The D-Bus interface of the changed properties.
+ </tp:docstring>
+ </arg>
+ <arg name="properties" type="a{sv}">
+ <tp:docstring>
+ The changed property names and their new values.
+ </tp:docstring>
+ </arg>
+ </signal>
+
+ <signal name="PropertiesChanged">
+ <tp:docstring>
+ One or more properties value changed; this signal implements the
+ D-Bus specification's PropertiesChanged signal.
+ </tp:docstring>
+ <arg name="interface" type="s">
+ <tp:docstring>
+ The D-Bus interface of the changed properties.
+ </tp:docstring>
+ </arg>
+ <arg name="changed_properties" type="a{sv}">
+ <tp:docstring>
+ The changed property names and their new values.
+ </tp:docstring>
+ </arg>
+ <arg name="invalidated_properties" type="as">
+ <tp:docstring>
+ Properties which are now invalid, but for which the new value is not
+ emitted in this signal. Clients interested in these properties should
+ issue a Get request for them to retrieve the new value.
+ </tp:docstring>
+ </arg>
+ </signal>
+ </interface>
+</node>
diff --git a/introspection/org.freedesktop.ModemManager.Modem.Cdma.xml b/introspection/org.freedesktop.ModemManager.Modem.Cdma.xml
new file mode 100644
index 0000000..d80d9b9
--- /dev/null
+++ b/introspection/org.freedesktop.ModemManager.Modem.Cdma.xml
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
+ <interface name="org.freedesktop.ModemManager.Modem.Cdma">
+
+ <method name="Activate">
+ <tp:docstring>
+ Activates the modem for use with a given carrier. In the
+ event of immediate failure, returns an error value instead of
+ setting a DBus error.
+ </tp:docstring>
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_cdma_activate"/>
+ <arg name="carrier" type="s" direction="in">
+ <tp:docstring>
+ Name of carrier.
+ </tp:docstring>
+ </arg>
+ <arg name="immediate_error" type="u" direction="out">
+ <tp:docstring>
+ An enum from MM_MODEM_CDMA_ACTIVATION_ERROR. This is
+ returned for immediate errors. Delayed errors are returned
+ via an ActivationStateChanged signal
+ </tp:docstring>
+ </arg>
+ </method>
+
+ <method name="ActivateManual">
+ <tp:docstring>
+ Sets modem configuration data. Unlike regular Activate(),
+ this does not contact the carrier. Some modems will reboot
+ after this call is made.
+ </tp:docstring>
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_cdma_activate_manual"/>
+ <arg name="properties" type="a{sv}" direction="in">
+ <tp:docstring>
+ A dictionary of properties to set on the modem. Keys include 'mdn', 'min'
+ </tp:docstring>
+ </arg>
+ </method>
+
+ <signal name="ActivationStateChanged">
+ <tp:docstring>
+ The device activation state changed.
+ </tp:docstring>
+ <arg name="activation_state" type="u" tp:type="MM_MODEM_CDMA_ACTIVATION_STATE">
+ <tp:docstring>Current activation state</tp:docstring>
+ </arg>
+ <arg name="activation_error" type="u" tp:type="MM_MODEM_CDMA_ACTIVATION_ERROR">
+ <tp:docstring>Carrier-specific error code</tp:docstring>
+ </arg>
+ <arg name="status_changes" type="a{sv}">
+ <tp:docstring>Selected Modem.Simple.GetStatus keys that have changed as a
+ result of this activation state change. Will include 'mdn'
+ and 'min'.
+ </tp:docstring>
+ </arg>
+ </signal>
+
+ <method name="GetSignalQuality">
+ <tp:docstring>
+ Get the current signal quality.
+ </tp:docstring>
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_cdma_get_signal_quality"/>
+ <arg name="quality" type="u" direction="out">
+ <tp:docstring>
+ Signal quality (percent).
+ </tp:docstring>
+ </arg>
+ </method>
+
+ <method name="GetEsn">
+ <tp:docstring>
+ Get the Electronic Serial Number of the card.
+ </tp:docstring>
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_cdma_get_esn"/>
+ <arg name="esn" type="s" direction="out">
+ <tp:docstring>
+ The ESN.
+ </tp:docstring>
+ </arg>
+ </method>
+
+ <method name="GetServingSystem">
+ <tp:docstring>
+ Get the Service System details of the current network, if registered.
+ </tp:docstring>
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_cdma_get_serving_system"/>
+ <arg name="info" type="(usu)" direction="out">
+ <tp:docstring>
+ A structure containing the Band Class (0 = unknown, 1 = 800 MHz, 2 = 1900 MHz), the Band ("A" - "F" as defined by IS707-A), and the System ID of the serving network.
+ </tp:docstring>
+ </arg>
+ </method>
+
+ <signal name="SignalQuality">
+ <tp:docstring>
+ The signal quality changed.
+ </tp:docstring>
+ <arg name="quality" type="u">
+ <tp:docstring>
+ The new quality in percent, 0..100.
+ </tp:docstring>
+ </arg>
+ </signal>
+
+ <method name="GetRegistrationState">
+ <tp:docstring>Get device registration state.</tp:docstring>
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_cdma_get_registration_state"/>
+ <arg name="cdma_1x_state" type="u" direction="out" tp:type="MM_MODEM_CDMA_REGISTRATION_STATE">
+ <tp:docstring>CDMA 1x registration state.</tp:docstring>
+ </arg>
+ <arg name="evdo_state" type="u" direction="out" tp:type="MM_MODEM_CDMA_REGISTRATION_STATE">
+ <tp:docstring>EVDO registration state.</tp:docstring>
+ </arg>
+ </method>
+
+ <property name="Meid" type="s" access="read">
+ <tp:docstring>
+ The modem's Mobile Equipment Identifier.
+ </tp:docstring>
+ </property>
+
+ <signal name="RegistrationStateChanged">
+ <tp:docstring>
+ The device registration state changed.
+ </tp:docstring>
+ <arg name="cdma-1x-state" type="u" tp:type="MM_MODEM_CDMA_REGISTRATION_STATE">
+ <tp:docstring>CDMA 1x registration state.</tp:docstring>
+ </arg>
+ <arg name="evdo-state" type="u" tp:type="MM_MODEM_CDMA_REGISTRATION_STATE">
+ <tp:docstring>EVDO registration state.</tp:docstring>
+ </arg>
+ </signal>
+
+ <tp:enum name="MM_MODEM_CDMA_REGISTRATION_STATE" type="u">
+ <tp:enumvalue suffix="UNKNOWN" value="0">
+ <tp:docstring>Registration status is unknown or the device is not registered.</tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="REGISTERED" value="1">
+ <tp:docstring>Registered, but roaming status is unknown or cannot be provided by the device. The device may or may not be roaming.</tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="HOME" value="2">
+ <tp:docstring>Currently registered on the home network.</tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="ROAMING" value="3">
+ <tp:docstring>Currently registered on a roaming network.</tp:docstring>
+ </tp:enumvalue>
+ </tp:enum>
+
+ <tp:enum name="MM_MODEM_CDMA_ACTIVATION_STATE" type="u">
+ <tp:enumvalue suffix="NOT_ACTIVATED" value="0">
+ <tp:docstring>Device is not activated</tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="ACTIVATING" value="1">
+ <tp:docstring>Device is activating</tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="PARTIALLY_ACTIVATED" value="2">
+ <tp:docstring>Device is partially activated; carrier-specific steps required to continue.</tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="ACTIVATED" value="3">
+ <tp:docstring>Device is ready for use.</tp:docstring>
+ </tp:enumvalue>
+ </tp:enum>
+
+ <tp:enum name="MM_MODEM_CDMA_ACTIVATION_ERROR" type="u">
+ <tp:enumvalue suffix="NO_ERROR" value="0"/>
+ <tp:enumvalue suffix="ROAMING" value="1">
+ <tp:docstring>
+ Device cannot activate while roaming.
+ </tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="WRONG_RADIO_INTERFACE" value="2">
+ <tp:docstring>
+ Device cannot activate on this network type (eg EVDO vs 1xRTT).
+ </tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="COULD_NOT_CONNECT" value="3">
+ <tp:docstring>
+ Device could not connect to the network for activation.
+ </tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="SECURITY_AUTHENTICATION_FAILED" value="4">
+ <tp:docstring>
+ Device could not authenticate to the network for activation.
+ </tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="PROVISIONING_FAILED" value="5">
+ <tp:docstring>
+ Later stages of device provisioning failed.
+ </tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="NO_SIGNAL" value="6">
+ <tp:docstring>
+ No signal available.
+ </tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="UNKNOWN" value="7">
+ <tp:docstring>
+ An error occurred.
+ </tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="TIMED_OUT" value="8">
+ <tp:docstring>
+ Activation timed out.
+ </tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="START_FAILED" value="9">
+ <tp:docstring>
+ API call for initial activation failed.
+ </tp:docstring>
+ </tp:enumvalue>
+ </tp:enum>
+ </interface>
+</node>
diff --git a/introspection/mm-modem-gsm-card.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml
index 9c9fdc1..d481157 100644
--- a/introspection/mm-modem-gsm-card.xml
+++ b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml
@@ -109,6 +109,14 @@
</arg>
</method>
+ <property name="SimIdentifier" type="s" access="read">
+ <tp:docstring>
+ An obfuscated SIM identifier based on the IMSI or the ICCID. This may
+ be available before the PIN has been entered depending on the device
+ itself.
+ </tp:docstring>
+ </property>
+
<property name="SupportedBands" type="u" access="read" tp:type="MM_MODEM_GSM_BAND">
<tp:docstring>
Bands supported by the card. (Note for plugin writers:
diff --git a/introspection/mm-modem-gsm-contacts.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Contacts.xml
index 60b06ad..60b06ad 100644
--- a/introspection/mm-modem-gsm-contacts.xml
+++ b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Contacts.xml
diff --git a/introspection/mm-modem-gsm-hso.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Hso.xml
index d646acc..d646acc 100644
--- a/introspection/mm-modem-gsm-hso.xml
+++ b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Hso.xml
diff --git a/introspection/mm-modem-gsm-network.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Network.xml
index 7c26681..7c26681 100644
--- a/introspection/mm-modem-gsm-network.xml
+++ b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Network.xml
diff --git a/introspection/mm-modem-gsm-sms.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.SMS.xml
index 081ecc5..081ecc5 100644
--- a/introspection/mm-modem-gsm-sms.xml
+++ b/introspection/org.freedesktop.ModemManager.Modem.Gsm.SMS.xml
diff --git a/introspection/mm-modem-gsm-ussd.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Ussd.xml
index ae6884f..8eef91d 100644
--- a/introspection/mm-modem-gsm-ussd.xml
+++ b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Ussd.xml
@@ -38,6 +38,12 @@
request for further input.
</tp:docstring>
</arg>
+ <arg name="reply" type="s" direction="out">
+ <tp:docstring>
+ The network reply to this response to the network-initiated USSD
+ command. The reply may require further responses.
+ </tp:docstring>
+ </arg>
</method>
<method name="Cancel">
diff --git a/introspection/mm-modem-gsm.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.xml
index ea23adc..78da9a4 100644
--- a/introspection/mm-modem-gsm.xml
+++ b/introspection/org.freedesktop.ModemManager.Modem.Gsm.xml
@@ -157,6 +157,9 @@
<tp:enumvalue suffix="HSPA" value="8">
<tp:docstring>HSPA (ETSI 27.007: "UTRAN w/HSDPA and HSUPA")</tp:docstring>
</tp:enumvalue>
+ <tp:enumvalue suffix="HSPA_PLUS" value="9">
+ <tp:docstring>HSPA+ (ETSI 27.007: "UTRAN w/HSPA+")</tp:docstring>
+ </tp:enumvalue>
</tp:enum>
</interface>
diff --git a/introspection/mm-modem-location.xml b/introspection/org.freedesktop.ModemManager.Modem.Location.xml
index 58dca68..d74f61c 100644
--- a/introspection/mm-modem-location.xml
+++ b/introspection/org.freedesktop.ModemManager.Modem.Location.xml
@@ -199,7 +199,7 @@
GetLocation() method or in the Location property.</p>
</tp:docstring>
</tp:flag>
- <tp:flag suffix="GSM_GPS_RAW" value="0x4">
+ <tp:flag suffix="GPS_RAW" value="0x4">
<tp:docstring>
<p>For capability reporting, indicates the device is capable of
providing raw GPS information using a series of defined key/value
diff --git a/introspection/mm-modem-simple.xml b/introspection/org.freedesktop.ModemManager.Modem.Simple.xml
index bee1017..bee1017 100644
--- a/introspection/mm-modem-simple.xml
+++ b/introspection/org.freedesktop.ModemManager.Modem.Simple.xml
diff --git a/introspection/mm-modem.xml b/introspection/org.freedesktop.ModemManager.Modem.xml
index 7d54dd3..3f6f0bb 100644
--- a/introspection/mm-modem.xml
+++ b/introspection/org.freedesktop.ModemManager.Modem.xml
@@ -2,24 +2,6 @@
<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
- <interface name="org.freedesktop.DBus.Properties">
- <signal name="MmPropertiesChanged">
- <tp:docstring>
- One or more properties' values changed.
- </tp:docstring>
- <arg name="interface" type="s">
- <tp:docstring>
- The D-Bus interface of the changed properties.
- </tp:docstring>
- </arg>
- <arg name="properties" type="a{sv}">
- <tp:docstring>
- The changed property names and their new values.
- </tp:docstring>
- </arg>
- </signal>
- </interface>
-
<interface name="org.freedesktop.ModemManager.Modem">
<method name="Enable">
<tp:docstring>
@@ -81,9 +63,20 @@
</arg>
</method>
+ <method name="Reset">
+ <tp:docstring>
+ Clear non-persistent configuration and state, and return the device to
+ a newly-powered-on state. This command may power-cycle the device.
+ </tp:docstring>
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_reset"/>
+ </method>
+
<method name="FactoryReset">
<tp:docstring>
- Reset the modem to as close to factory state as possible.
+ Clear the modem's configuration (including persistent configuration and
+ state), and return the device to a factory-default state. This command
+ may or may not power-cycle the device.
</tp:docstring>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_factory_reset"/>
@@ -92,12 +85,45 @@
</arg>
</method>
+ <signal name="StateChanged">
+ <tp:docstring>
+ The modem's state (see the State property) changed.
+ </tp:docstring>
+ <arg name="old" type="u">
+ <tp:docstring>
+ Old state.
+ </tp:docstring>
+ </arg>
+ <arg name="new" type="u">
+ <tp:docstring>
+ New state.
+ </tp:docstring>
+ </arg>
+ <arg name="reason" type="u" tp:type="MM_MODEM_STATE_CHANGED_REASON">
+ <tp:docstring>
+ Reason for this state change.
+ </tp:docstring>
+ </arg>
+ </signal>
+
<property name="Device" type="s" access="read">
<tp:docstring>
The modem port to use for IP configuration and traffic.
</tp:docstring>
</property>
+ <property name="DeviceIdentifier" type="s" access="read">
+ <tp:docstring>
+ A best-effort device identifier based on various device information like
+ model name, firmware revision, USB/PCI/PCMCIA IDs, and other properties.
+ This ID is not guaranteed to be unique and may be shared between
+ identical devices with the same firmware, but is intended to be
+ "unique enough" for use as a casual device identifier for various
+ user experience operations. This is not the device's IMEI or ESN since
+ those may not be available before unlocking the device via a PIN.
+ </tp:docstring>
+ </property>
+
<property name="MasterDevice" type="s" access="read">
<tp:docstring>
The physical modem device reference (ie, USB, PCI, PCMCIA device), which
@@ -156,6 +182,15 @@
</tp:docstring>
</property>
+ <!-- This ought to be of tp:type="MM_MODEM_STATE" but there are a couple
+ more wrinkles to be sorted out before we can export that here.
+ Also, Enabled should be folded into this. -->
+ <property name="State" type="u" access="read">
+ <tp:docstring>
+ State of the modem.
+ </tp:docstring>
+ </property>
+
<tp:enum name="MM_MODEM_TYPE" type="u">
<tp:enumvalue suffix="GSM" value="1">
<tp:docstring>
@@ -187,5 +222,24 @@
</tp:enumvalue>
</tp:enum>
+ <tp:enum name="MM_MODEM_STATE_CHANGED_REASON" type="u">
+ <tp:enumvalue suffix="UNKNOWN" value="0">
+ <tp:docstring>
+ Reason unknown or not reportable.
+ </tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="USER_REQUESTED" value="1">
+ <tp:docstring>
+ State change was requested by an interface user.
+ </tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="SUSPEND" value="2">
+ <tp:docstring>
+ State change was caused by a system suspend.
+ </tp:docstring>
+ </tp:enumvalue>
+ </tp:enum>
+
+
</interface>
</node>
diff --git a/introspection/mm-manager.xml b/introspection/org.freedesktop.ModemManager.xml
index bdeac01..bdeac01 100644
--- a/introspection/mm-manager.xml
+++ b/introspection/org.freedesktop.ModemManager.xml
diff --git a/libqcdm/src/Makefile.am b/libqcdm/src/Makefile.am
index 5cc0568..f9451c6 100644
--- a/libqcdm/src/Makefile.am
+++ b/libqcdm/src/Makefile.am
@@ -22,9 +22,6 @@ libqcdm_la_SOURCES = \
libqcdm_la_LIBADD = \
$(MM_LIBS)
-libqcdm_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libqcdm.ver \
- -version-info "0:0:0"
-
###########################################
# Test library without symbol versioning
diff --git a/libqcdm/src/commands.c b/libqcdm/src/commands.c
index 11a1a38..ab61ee5 100644
--- a/libqcdm/src/commands.c
+++ b/libqcdm/src/commands.c
@@ -119,6 +119,8 @@ bin2hexstr (const guint8 *bytes, int len)
return result;
}
+/**********************************************************************/
+
static gboolean
check_command (const char *buf, gsize len, guint8 cmd, gsize min_len, GError **error)
{
@@ -154,6 +156,11 @@ check_command (const char *buf, gsize len, guint8 cmd, gsize min_len, GError **e
"DM command %d not allowed in the current device mode",
cmd);
return FALSE;
+ case DIAG_CMD_BAD_SPC_MODE:
+ g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_SPC_LOCKED,
+ "DM command %d not allowed because the Service Programming Code is locked",
+ cmd);
+ return FALSE;
default:
break;
}
@@ -431,6 +438,52 @@ qcdm_cmd_sw_version_result (const char *buf, gsize len, GError **error)
/**********************************************************************/
gsize
+qcdm_cmd_status_snapshot_new (char *buf, gsize len, GError **error)
+{
+ char cmdbuf[3];
+ DMCmdHeader *cmd = (DMCmdHeader *) &cmdbuf[0];
+
+ g_return_val_if_fail (buf != NULL, 0);
+ g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0);
+
+ memset (cmd, 0, sizeof (*cmd));
+ cmd->code = DIAG_CMD_STATUS_SNAPSHOT;
+
+ return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len);
+}
+
+static guint8
+snapshot_state_to_qcdm (guint8 cdma_state)
+{
+ /* CDMA_STATUS_SNAPSHOT_STATE_* -> QCDM_STATUS_SNAPSHOT_STATE_* */
+ return cdma_state + 1;
+}
+
+QCDMResult *
+qcdm_cmd_status_snapshot_result (const char *buf, gsize len, GError **error)
+{
+ QCDMResult *result = NULL;
+ DMCmdStatusSnapshotRsp *rsp = (DMCmdStatusSnapshotRsp *) buf;
+
+ g_return_val_if_fail (buf != NULL, NULL);
+
+ if (!check_command (buf, len, DIAG_CMD_STATUS_SNAPSHOT, sizeof (*rsp), error))
+ return NULL;
+
+ result = qcdm_result_new ();
+
+ qcdm_result_add_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_BAND_CLASS, cdma_band_class_to_qcdm (rsp->band_class));
+ qcdm_result_add_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_BASE_STATION_PREV, cdma_prev_to_qcdm (rsp->prev));
+ qcdm_result_add_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_MOBILE_PREV, cdma_prev_to_qcdm (rsp->mob_prev));
+ qcdm_result_add_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_PREV_IN_USE, cdma_prev_to_qcdm (rsp->prev_in_use));
+ qcdm_result_add_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_STATE, snapshot_state_to_qcdm (rsp->state & 0xF));
+
+ return result;
+}
+
+/**********************************************************************/
+
+gsize
qcdm_cmd_pilot_sets_new (char *buf, gsize len, GError **error)
{
char cmdbuf[3];
@@ -820,6 +873,107 @@ qcdm_cmd_nv_set_mode_pref_result (const char *buf, gsize len, GError **error)
/**********************************************************************/
+static gboolean
+hdr_rev_pref_validate (guint8 dm)
+{
+ if ( dm == DIAG_NV_HDR_REV_PREF_0
+ || dm == DIAG_NV_HDR_REV_PREF_A
+ || dm == DIAG_NV_HDR_REV_PREF_EHRPD)
+ return TRUE;
+ return FALSE;
+}
+
+gsize
+qcdm_cmd_nv_get_hdr_rev_pref_new (char *buf, gsize len, GError **error)
+{
+ char cmdbuf[sizeof (DMCmdNVReadWrite) + 2];
+ DMCmdNVReadWrite *cmd = (DMCmdNVReadWrite *) &cmdbuf[0];
+
+ g_return_val_if_fail (buf != NULL, 0);
+ g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0);
+
+ memset (cmd, 0, sizeof (*cmd));
+ cmd->code = DIAG_CMD_NV_READ;
+ cmd->nv_item = GUINT16_TO_LE (DIAG_NV_HDR_REV_PREF);
+
+ return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len);
+}
+
+QCDMResult *
+qcdm_cmd_nv_get_hdr_rev_pref_result (const char *buf, gsize len, GError **error)
+{
+ QCDMResult *result = NULL;
+ DMCmdNVReadWrite *rsp = (DMCmdNVReadWrite *) buf;
+ DMNVItemHdrRevPref *rev;
+
+ g_return_val_if_fail (buf != NULL, NULL);
+
+ if (!check_command (buf, len, DIAG_CMD_NV_READ, sizeof (DMCmdNVReadWrite), error))
+ return NULL;
+
+ if (!check_nv_cmd (rsp, DIAG_NV_HDR_REV_PREF, error))
+ return NULL;
+
+ rev = (DMNVItemHdrRevPref *) &rsp->data[0];
+
+ if (!hdr_rev_pref_validate (rev->rev_pref)) {
+ g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_PARAMETER,
+ "Unknown HDR revision preference 0x%X",
+ rev->rev_pref);
+ return NULL;
+ }
+
+ result = qcdm_result_new ();
+ qcdm_result_add_uint8 (result, QCDM_CMD_NV_GET_HDR_REV_PREF_ITEM_REV_PREF, rev->rev_pref);
+
+ return result;
+}
+
+gsize
+qcdm_cmd_nv_set_hdr_rev_pref_new (char *buf,
+ gsize len,
+ guint8 rev_pref,
+ GError **error)
+{
+ char cmdbuf[sizeof (DMCmdNVReadWrite) + 2];
+ DMCmdNVReadWrite *cmd = (DMCmdNVReadWrite *) &cmdbuf[0];
+ DMNVItemHdrRevPref *req;
+
+ g_return_val_if_fail (buf != NULL, 0);
+ g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0);
+
+ if (!hdr_rev_pref_validate (rev_pref)) {
+ g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_PARAMETER,
+ "Invalid HDR revision preference %d", rev_pref);
+ return 0;
+ }
+
+ memset (cmd, 0, sizeof (*cmd));
+ cmd->code = DIAG_CMD_NV_WRITE;
+ cmd->nv_item = GUINT16_TO_LE (DIAG_NV_HDR_REV_PREF);
+
+ req = (DMNVItemHdrRevPref *) &cmd->data[0];
+ req->rev_pref = rev_pref;
+
+ return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len);
+}
+
+QCDMResult *
+qcdm_cmd_nv_set_hdr_rev_pref_result (const char *buf, gsize len, GError **error)
+{
+ g_return_val_if_fail (buf != NULL, NULL);
+
+ if (!check_command (buf, len, DIAG_CMD_NV_WRITE, sizeof (DMCmdNVReadWrite), error))
+ return NULL;
+
+ if (!check_nv_cmd ((DMCmdNVReadWrite *) buf, DIAG_NV_HDR_REV_PREF, error))
+ return NULL;
+
+ return qcdm_result_new ();
+}
+
+/**********************************************************************/
+
gsize
qcdm_cmd_cm_subsys_state_info_new (char *buf, gsize len, GError **error)
{
@@ -940,6 +1094,137 @@ qcdm_cmd_hdr_subsys_state_info_result (const char *buf, gsize len, GError **erro
/**********************************************************************/
gsize
+qcdm_cmd_ext_logmask_new (char *buf,
+ gsize len,
+ GSList *items,
+ guint16 maxlog,
+ GError **error)
+{
+ char cmdbuf[sizeof (DMCmdExtLogMask) + 2];
+ DMCmdExtLogMask *cmd = (DMCmdExtLogMask *) &cmdbuf[0];
+ GSList *iter;
+ guint16 highest = 0;
+ gsize total = 3;
+
+ g_return_val_if_fail (buf != NULL, 0);
+ g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0);
+
+ memset (cmd, 0, sizeof (*cmd));
+ cmd->code = DIAG_CMD_EXT_LOGMASK;
+
+ for (iter = items; iter; iter = g_slist_next (iter)) {
+ guint32 item = GPOINTER_TO_UINT (iter->data);
+
+ g_warn_if_fail (item > 0);
+ g_warn_if_fail (item < 4095);
+ cmd->mask[item / 8] |= 1 << item % 8;
+
+ if (item > highest)
+ highest = item;
+ }
+
+ g_return_val_if_fail (highest <= maxlog, 0);
+ cmd->len = GUINT16_TO_LE (maxlog);
+ total += maxlog / 8;
+ if (maxlog && maxlog % 8)
+ total++;
+
+ return dm_encapsulate_buffer (cmdbuf, total, sizeof (cmdbuf), buf, len);
+}
+
+QCDMResult *
+qcdm_cmd_ext_logmask_result (const char *buf,
+ gsize len,
+ GError **error)
+{
+ QCDMResult *result = NULL;
+ DMCmdExtLogMask *rsp = (DMCmdExtLogMask *) buf;
+ guint32 masklen = 0, maxlog = 0;
+ gsize minlen = 0;
+
+ g_return_val_if_fail (buf != NULL, NULL);
+
+ /* Ensure size is at least enough for the command header */
+ if (len < 1) {
+ g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_LENGTH,
+ "DM command %d response not long enough (got %zu, expected "
+ "at least %d).", DIAG_CMD_EXT_LOGMASK, len, 3);
+ return FALSE;
+ }
+
+ /* Result of a 'set' operation will be only 1 byte in size; result of
+ * a 'get' operation (ie setting len to 0x0000 in the request) will be
+ * the size of the header (3) plus the max log length.
+ */
+
+ if (len == 1)
+ minlen = 1;
+ else {
+ /* Ensure size is equal to max # of log items + 3 */
+ maxlog = GUINT16_FROM_LE (rsp->len);
+ masklen = maxlog / 8;
+ if (maxlog % 8)
+ masklen++;
+
+ if (len < (masklen + 3)) {
+ g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_LENGTH,
+ "DM command %d response not long enough (got %zu, expected "
+ "at least %d).", DIAG_CMD_EXT_LOGMASK, len, masklen + 3);
+ return FALSE;
+ }
+ minlen = masklen + 3;
+ }
+
+ if (!check_command (buf, len, DIAG_CMD_EXT_LOGMASK, minlen, error))
+ return NULL;
+
+ result = qcdm_result_new ();
+
+ if (minlen != 4)
+ qcdm_result_add_uint32 (result, QCDM_CMD_EXT_LOGMASK_ITEM_MAX_ITEMS, maxlog);
+
+ return result;
+}
+
+gboolean
+qcmd_cmd_ext_logmask_result_get_item (QCDMResult *result,
+ guint16 item)
+{
+ return FALSE;
+}
+
+/**********************************************************************/
+
+gsize
+qcdm_cmd_event_report_new (char *buf, gsize len, gboolean start, GError **error)
+{
+ char cmdbuf[4];
+ DMCmdEventReport *cmd = (DMCmdEventReport *) &cmdbuf[0];
+
+ g_return_val_if_fail (buf != NULL, 0);
+ g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0);
+
+ memset (cmd, 0, sizeof (*cmd));
+ cmd->code = DIAG_CMD_EVENT_REPORT;
+ cmd->on = start ? 1 : 0;
+
+ return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len);
+}
+
+QCDMResult *
+qcdm_cmd_event_report_result (const char *buf, gsize len, GError **error)
+{
+ g_return_val_if_fail (buf != NULL, NULL);
+
+ if (!check_command (buf, len, DIAG_CMD_EVENT_REPORT, sizeof (DMCmdEventReport), error))
+ return NULL;
+
+ return qcdm_result_new ();
+}
+
+/**********************************************************************/
+
+gsize
qcdm_cmd_zte_subsys_status_new (char *buf, gsize len, GError **error)
{
char cmdbuf[sizeof (DMCmdSubsysHeader) + 2];
diff --git a/libqcdm/src/commands.h b/libqcdm/src/commands.h
index 75e83a7..fe582a6 100644
--- a/libqcdm/src/commands.h
+++ b/libqcdm/src/commands.h
@@ -148,6 +148,54 @@ QCDMResult *qcdm_cmd_sw_version_result (const char *buf,
/**********************************************************************/
+/* One of QCDM_CDMA_BAND_CLASS_* */
+#define QCDM_CMD_STATUS_SNAPSHOT_ITEM_BAND_CLASS "band-class"
+
+/* The protocol revision of the base station. One of QCDM_CDMA_PREV_* */
+#define QCDM_CMD_STATUS_SNAPSHOT_ITEM_BASE_STATION_PREV "prev"
+
+/* The protocol revision of the mobile terminal. One of QCDM_CDMA_PREV_* */
+#define QCDM_CMD_STATUS_SNAPSHOT_ITEM_MOBILE_PREV "mob-prev"
+
+/* The protocol revision currently in-use. One of QCDM_CDMA_PREV_* */
+#define QCDM_CMD_STATUS_SNAPSHOT_ITEM_PREV_IN_USE "prev-in-use"
+
+enum {
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_UNKNOWN = 0x00,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_NO_SERVICE = 0x01,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_INITIALIZATION = 0x02,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_IDLE = 0x03,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_VOICE_CHANNEL_INIT = 0x04,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_WAITING_FOR_ORDER = 0x05,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_WAITING_FOR_ANSWER = 0x06,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_CONVERSATION = 0x07,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_RELEASE = 0x08,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_SYSTEM_ACCESS = 0x09,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_OFFLINE_CDMA = 0x11,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_OFFLINE_HDR = 0x12,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_OFFLINE_ANALOG = 0x13,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_RESET = 0x14,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_POWER_DOWN = 0x15,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_POWER_SAVE = 0x16,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_POWER_UP = 0x17,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_LOW_POWER_MODE = 0x18,
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_SEARCHER_DSMM = 0x19, /* Dedicated System Measurement Mode */
+ QCDM_CMD_STATUS_SNAPSHOT_STATE_HDR = 0x41,
+};
+
+/* The protocol revision currently in-use. One of QCDM_STATUS_SNAPSHOT_STATE_* */
+#define QCDM_CMD_STATUS_SNAPSHOT_ITEM_STATE "state"
+
+gsize qcdm_cmd_status_snapshot_new (char *buf,
+ gsize len,
+ GError **error);
+
+QCDMResult *qcdm_cmd_status_snapshot_result (const char *buf,
+ gsize len,
+ GError **error);
+
+/**********************************************************************/
+
enum {
QCDM_CMD_PILOT_SETS_TYPE_UNKNOWN = 0,
QCDM_CMD_PILOT_SETS_TYPE_ACTIVE = 1,
@@ -252,6 +300,34 @@ QCDMResult *qcdm_cmd_nv_set_mode_pref_result (const char *buf,
/**********************************************************************/
+/* Values for QCDM_CMD_NV_GET_HDR_REV_PREF_ITEM_REV_PREF */
+enum {
+ QCDM_CMD_NV_HDR_REV_PREF_ITEM_REV_PREF_0 = 0x00,
+ QCDM_CMD_NV_HDR_REV_PREF_ITEM_REV_PREF_A = 0x01,
+ QCDM_CMD_NV_HDR_REV_PREF_ITEM_REV_PREF_EHRPD = 0x04,
+};
+
+#define QCDM_CMD_NV_GET_HDR_REV_PREF_ITEM_REV_PREF "rev-pref"
+
+gsize qcdm_cmd_nv_get_hdr_rev_pref_new (char *buf,
+ gsize len,
+ GError **error);
+
+QCDMResult *qcdm_cmd_nv_get_hdr_rev_pref_result (const char *buf,
+ gsize len,
+ GError **error);
+
+gsize qcdm_cmd_nv_set_hdr_rev_pref_new (char *buf,
+ gsize len,
+ guint8 rev_pref,
+ GError **error);
+
+QCDMResult *qcdm_cmd_nv_set_hdr_rev_pref_result (const char *buf,
+ gsize len,
+ GError **error);
+
+/**********************************************************************/
+
/* Values for QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_OPERATING_MODE */
enum {
QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_ONLINE = 5
@@ -265,7 +341,10 @@ enum {
QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_GSM = 3,
QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_HDR = 4,
QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_WCDMA = 5,
- QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_GPS = 6
+ QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_GPS = 6,
+ QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_GW = 7, /* GSM & WCDMA */
+ QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_WLAN = 8,
+ QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_LTE = 9,
};
/* Values for QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_ROAM_PREF */
@@ -392,6 +471,36 @@ QCDMResult *qcdm_cmd_hdr_subsys_state_info_result (const char *buf,
/**********************************************************************/
+/* Max # of log items this device supports */
+#define QCDM_CMD_EXT_LOGMASK_ITEM_MAX_ITEMS "max-items"
+
+gsize qcdm_cmd_ext_logmask_new (char *buf,
+ gsize len,
+ GSList *items,
+ guint16 maxlog,
+ GError **error);
+
+QCDMResult *qcdm_cmd_ext_logmask_result (const char *buf,
+ gsize len,
+ GError **error);
+
+/* Returns TRUE if 'item' is set in the log mask */
+gboolean qcmd_cmd_ext_logmask_result_get_item (QCDMResult *result,
+ guint16 item);
+
+/**********************************************************************/
+
+gsize qcdm_cmd_event_report_new (char *buf,
+ gsize len,
+ gboolean start,
+ GError **error);
+
+QCDMResult *qcdm_cmd_event_report_result (const char *buf,
+ gsize len,
+ GError **error);
+
+/**********************************************************************/
+
#define QCDM_CMD_ZTE_SUBSYS_STATUS_ITEM_SIGNAL_INDICATOR "signal-indicator"
gsize qcdm_cmd_zte_subsys_status_new (char *buf,
diff --git a/libqcdm/src/dm-commands.h b/libqcdm/src/dm-commands.h
index cfc98f7..6ce3c5d 100644
--- a/libqcdm/src/dm-commands.h
+++ b/libqcdm/src/dm-commands.h
@@ -180,6 +180,28 @@ enum {
CDMA_BAND_CLASS_12_PAMR_800 = 12
};
+enum {
+ CDMA_STATUS_SNAPSHOT_STATE_NO_SERVICE = 0x00,
+ CDMA_STATUS_SNAPSHOT_STATE_INITIALIZATION = 0x01,
+ CDMA_STATUS_SNAPSHOT_STATE_IDLE = 0x02,
+ CDMA_STATUS_SNAPSHOT_STATE_VOICE_CHANNEL_INIT = 0x03,
+ CDMA_STATUS_SNAPSHOT_STATE_WAITING_FOR_ORDER = 0x04,
+ CDMA_STATUS_SNAPSHOT_STATE_WAITING_FOR_ANSWER = 0x05,
+ CDMA_STATUS_SNAPSHOT_STATE_CONVERSATION = 0x06,
+ CDMA_STATUS_SNAPSHOT_STATE_RELEASE = 0x07,
+ CDMA_STATUS_SNAPSHOT_STATE_SYSTEM_ACCESS = 0x08,
+ CDMA_STATUS_SNAPSHOT_STATE_OFFLINE_CDMA = 0x10,
+ CDMA_STATUS_SNAPSHOT_STATE_OFFLINE_HDR = 0x11,
+ CDMA_STATUS_SNAPSHOT_STATE_OFFLINE_ANALOG = 0x12,
+ CDMA_STATUS_SNAPSHOT_STATE_RESET = 0x13,
+ CDMA_STATUS_SNAPSHOT_STATE_POWER_DOWN = 0x14,
+ CDMA_STATUS_SNAPSHOT_STATE_POWER_SAVE = 0x15,
+ CDMA_STATUS_SNAPSHOT_STATE_POWER_UP = 0x16,
+ CDMA_STATUS_SNAPSHOT_STATE_LOW_POWER_MODE = 0x17,
+ CDMA_STATUS_SNAPSHOT_STATE_SEARCHER_DSMM = 0x18, /* Dedicated System Measurement Mode */
+ CDMA_STATUS_SNAPSHOT_STATE_HDR = 0x40,
+};
+
/* Generic DM command header */
struct DMCmdHeader {
guint8 code;
@@ -265,6 +287,29 @@ struct DMCmdSwVersionRsp {
} __attribute__ ((packed));
typedef struct DMCmdSwVersionRsp DMCmdSwVersionRsp;
+/* DIAG_CMD_STATUS_SNAPSHOT */
+struct DMCmdStatusSnapshotRsp {
+ guint8 code;
+ guint8 esn[4];
+ guint8 imsi_s1[4];
+ guint8 imsi_s2[2];
+ guint8 imsi_s[8];
+ guint8 imsi_11_12;
+ guint16 mcc;
+ guint8 imsi_addr_num;
+ guint16 sid;
+ guint16 nid;
+ guint8 prev;
+ guint8 prev_in_use;
+ guint8 mob_prev;
+ guint8 band_class;
+ guint16 frequency;
+ guint8 oper_mode;
+ guint8 state;
+ guint8 sub_state;
+} __attribute__ ((packed));
+typedef struct DMCmdStatusSnapshotRsp DMCmdStatusSnapshotRsp;
+
/* DIAG_SUBSYS_CM_STATE_INFO subsys command */
struct DMCmdSubsysCMStateInfoRsp {
DMCmdSubsysHeader header;
@@ -323,6 +368,29 @@ struct DMCmdPilotSetsRsp {
} __attribute__ ((packed));
typedef struct DMCmdPilotSetsRsp DMCmdPilotSetsRsp;
+struct DMCmdExtLogMask {
+ guint8 code;
+ /* Bit number of highest '1' in 'mask'; set to 0 to get current mask. */
+ guint16 len;
+ /* Bitfield of log messages to receive */
+ guint8 mask[512];
+} __attribute__ ((packed));
+typedef struct DMCmdExtLogMask DMCmdExtLogMask;
+
+struct DMCmdEventReport {
+ guint8 code;
+ guint8 on;
+} __attribute__ ((packed));
+typedef struct DMCmdEventReport DMCmdEventReport;
+
+struct DMCmdEventReportRsp {
+ guint8 code;
+ guint16 len;
+ guint16 event_id;
+ guint8 data[0];
+} __attribute__ ((packed));
+typedef struct DMCmdEventReportRsp DMCmdEventReportRsp;
+
/* DIAG_SUBSYS_NW_CONTROL_* subsys command */
struct DMCmdSubsysNwSnapshotReq {
DMCmdSubsysHeader hdr;
diff --git a/libqcdm/src/error.c b/libqcdm/src/error.c
index e3b97a0..994608e 100644
--- a/libqcdm/src/error.c
+++ b/libqcdm/src/error.c
@@ -75,6 +75,7 @@ qcdm_command_error_get_type (void)
ENUM_ENTRY (QCDM_COMMAND_NOT_ACCEPTED, "QcdmCommandNotAccepted"),
ENUM_ENTRY (QCDM_COMMAND_BAD_MODE, "QcdmCommandBadMode"),
ENUM_ENTRY (QCDM_COMMAND_NVCMD_FAILED, "QcdmCommandNvCmdFailed"),
+ ENUM_ENTRY (QCDM_COMMAND_SPC_LOCKED, "QcdmCommandSpcLocked"),
{ 0, 0, 0 }
};
diff --git a/libqcdm/src/error.h b/libqcdm/src/error.h
index 7a02ae2..f0b0534 100644
--- a/libqcdm/src/error.h
+++ b/libqcdm/src/error.h
@@ -41,6 +41,7 @@ enum {
QCDM_COMMAND_NOT_ACCEPTED = 5,
QCDM_COMMAND_BAD_MODE = 6,
QCDM_COMMAND_NVCMD_FAILED = 7,
+ QCDM_COMMAND_SPC_LOCKED = 8,
};
#define QCDM_COMMAND_ERROR (qcdm_command_error_quark ())
diff --git a/libqcdm/src/libqcdm.ver b/libqcdm/src/libqcdm.ver
deleted file mode 100644
index b1567e2..0000000
--- a/libqcdm/src/libqcdm.ver
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-global:
- nm_vpn_connection_new;
-local:
- *;
-};
diff --git a/libqcdm/src/nv-items.h b/libqcdm/src/nv-items.h
index a0ca10a..8240866 100644
--- a/libqcdm/src/nv-items.h
+++ b/libqcdm/src/nv-items.h
@@ -19,17 +19,21 @@
#define LIBQCDM_NV_ITEMS_H
enum {
- DIAG_NV_MODE_PREF = 10, /* Mode preference: 1x, HDR, auto */
- DIAG_NV_DIR_NUMBER = 178, /* Mobile Directory Number (MDN) */
- DIAG_NV_ROAM_PREF = 442, /* Roaming preference */
+ DIAG_NV_MODE_PREF = 10, /* Mode preference: 1x, HDR, auto */
+ DIAG_NV_DIR_NUMBER = 178, /* Mobile Directory Number (MDN) */
+ DIAG_NV_ROAM_PREF = 442, /* Roaming preference */
+ DIAG_NV_HDR_REV_PREF = 4964, /* HDR mode preference(?): rev0, revA, eHRPD */
};
/* Mode preference values */
enum {
- DIAG_NV_MODE_PREF_AUTO = 0x04,
- DIAG_NV_MODE_PREF_1X_ONLY = 0x09,
- DIAG_NV_MODE_PREF_HDR_ONLY = 0x0A,
+ DIAG_NV_MODE_PREF_AUTO = 0x04,
+ DIAG_NV_MODE_PREF_1X_ONLY = 0x09,
+ DIAG_NV_MODE_PREF_HDR_ONLY = 0x0A,
+ DIAG_NV_MODE_PREF_1X_HDR_ONLY = 0x0D,
+ DIAG_NV_MODE_PREF_LTE_ONLY = 0x1E,
+ DIAG_NV_MODE_PREF_1X_HDR_LTE_ONLY = 0x24,
};
/* DIAG_NV_MODE_PREF */
@@ -60,5 +64,18 @@ struct DMNVItemRoamPref {
} __attribute__ ((packed));
typedef struct DMNVItemRoamPref DMNVItemRoamPref;
+/* HDR Revision preference values (?) */
+enum {
+ DIAG_NV_HDR_REV_PREF_0 = 0x00,
+ DIAG_NV_HDR_REV_PREF_A = 0x01,
+ DIAG_NV_HDR_REV_PREF_EHRPD = 0x04,
+};
+
+/* DIAG_NV_HDR_REV_PREF */
+struct DMNVItemHdrRevPref {
+ guint8 rev_pref;
+} __attribute__ ((packed));
+typedef struct DMNVItemHdrRevPref DMNVItemHdrRevPref;
+
#endif /* LIBQCDM_NV_ITEMS_H */
diff --git a/libqcdm/tests/test-qcdm-com.c b/libqcdm/tests/test-qcdm-com.c
index f41d249..b95c7d9 100644
--- a/libqcdm/tests/test-qcdm-com.c
+++ b/libqcdm/tests/test-qcdm-com.c
@@ -38,19 +38,19 @@ prev_to_string (guint8 prev)
{
switch (prev) {
case QCDM_CDMA_PREV_IS_95:
- return "IS-95";
+ return "1 (IS-95)";
case QCDM_CDMA_PREV_IS_95A:
- return "IS-95A";
+ return "2 (IS-95A)";
case QCDM_CDMA_PREV_IS_95A_TSB74:
- return "IS-95A TSB-74";
+ return "3 (IS-95A TSB-74)";
case QCDM_CDMA_PREV_IS_95B_PHASE1:
- return "IS-95B Phase I";
+ return "4 (IS-95B Phase I)";
case QCDM_CDMA_PREV_IS_95B_PHASE2:
- return "IS-95B Phase II";
+ return "5 (IS-95B Phase II)";
case QCDM_CDMA_PREV_IS2000_REL0:
- return "IS-2000 Release 0";
+ return "6 (IS-2000 Release 0)";
case QCDM_CDMA_PREV_IS2000_RELA:
- return "IS-2000 Release A";
+ return "7 (IS-2000 Release A)";
default:
break;
}
@@ -107,6 +107,54 @@ hdr_rev_to_string (guint8 hdr_rev)
return "unknown";
}
+static const char *
+status_snapshot_state_to_string (guint8 state)
+{
+ switch (state) {
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_NO_SERVICE:
+ return "no service";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_INITIALIZATION:
+ return "initialization";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_IDLE:
+ return "idle";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_VOICE_CHANNEL_INIT:
+ return "voice channel init";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_WAITING_FOR_ORDER:
+ return "waiting for order";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_WAITING_FOR_ANSWER:
+ return "waiting for answer";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_CONVERSATION:
+ return "conversation";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_RELEASE:
+ return "release";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_SYSTEM_ACCESS:
+ return "system access";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_OFFLINE_CDMA:
+ return "offline CDMA";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_OFFLINE_HDR:
+ return "offline HDR";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_OFFLINE_ANALOG:
+ return "offline analog";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_RESET:
+ return "reset";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_POWER_DOWN:
+ return "power down";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_POWER_SAVE:
+ return "power save";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_POWER_UP:
+ return "power up";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_LOW_POWER_MODE:
+ return "low power mode";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_SEARCHER_DSMM:
+ return "searcher DSMM";
+ case QCDM_CMD_STATUS_SNAPSHOT_STATE_HDR:
+ return "HDR";
+ default:
+ break;
+ }
+ return "unknown";
+}
+
/************************************************************/
typedef struct {
@@ -442,6 +490,9 @@ test_com_read_roam_pref (void *f, void *data)
/* Parse the response into a result structure */
result = qcdm_cmd_nv_get_roam_pref_result (buf, reply_len, &error);
+ if (error && (error->code == QCDM_COMMAND_NVCMD_FAILED))
+ return;
+
g_assert (result);
g_print ("\n");
@@ -493,7 +544,9 @@ test_com_read_mode_pref (void *f, void *data)
/* Parse the response into a result structure */
result = qcdm_cmd_nv_get_mode_pref_result (buf, reply_len, &error);
if (!result) {
- g_assert_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_NVCMD_FAILED);
+ g_assert (error);
+ g_assert (error->domain == QCDM_COMMAND_ERROR);
+ g_assert (error->code == QCDM_COMMAND_NVCMD_FAILED || error->code == QCDM_COMMAND_BAD_PARAMETER);
return;
}
@@ -522,6 +575,62 @@ test_com_read_mode_pref (void *f, void *data)
}
void
+test_com_read_hdr_rev_pref (void *f, void *data)
+{
+ TestComData *d = data;
+ gboolean success;
+ GError *error = NULL;
+ char buf[512];
+ guint8 pref;
+ const char *msg;
+ gint len;
+ QCDMResult *result;
+ gsize reply_len;
+
+ len = qcdm_cmd_nv_get_hdr_rev_pref_new (buf, sizeof (buf), NULL);
+ g_assert (len > 0);
+
+ /* Send the command */
+ success = send_command (d, buf, len);
+ g_assert (success);
+
+ /* Get a response */
+ reply_len = wait_reply (d, buf, sizeof (buf));
+
+ /* Parse the response into a result structure */
+ result = qcdm_cmd_nv_get_hdr_rev_pref_result (buf, reply_len, &error);
+ if (!result) {
+ g_assert (error);
+ g_assert (error->domain == QCDM_COMMAND_ERROR);
+ g_assert (error->code == QCDM_COMMAND_NVCMD_FAILED || error->code == QCDM_COMMAND_BAD_PARAMETER);
+ return;
+ }
+
+ g_print ("\n");
+
+ success = qcdm_result_get_uint8 (result, QCDM_CMD_NV_GET_HDR_REV_PREF_ITEM_REV_PREF, &pref);
+ g_assert (success);
+
+ switch (pref) {
+ case QCDM_CMD_NV_HDR_REV_PREF_ITEM_REV_PREF_0:
+ msg = "rev0";
+ break;
+ case QCDM_CMD_NV_HDR_REV_PREF_ITEM_REV_PREF_A:
+ msg = "revA";
+ break;
+ case QCDM_CMD_NV_HDR_REV_PREF_ITEM_REV_PREF_EHRPD:
+ msg = "eHRPD";
+ break;
+ default:
+ msg = "unknown";
+ break;
+ }
+ g_message ("%s: HDR rev preference: 0x%02X (%s)", __func__, pref, msg);
+
+ qcdm_result_unref (result);
+}
+
+void
test_com_status (void *f, void *data)
{
TestComData *d = data;
@@ -684,6 +793,57 @@ test_com_sw_version (void *f, void *data)
}
void
+test_com_status_snapshot (void *f, void *data)
+{
+ TestComData *d = data;
+ gboolean success;
+ GError *error = NULL;
+ char buf[100];
+ gint len;
+ QCDMResult *result;
+ gsize reply_len;
+ guint8 n8;
+
+ len = qcdm_cmd_status_snapshot_new (buf, sizeof (buf), NULL);
+ g_assert (len == 4);
+
+ /* Send the command */
+ success = send_command (d, buf, len);
+ g_assert (success);
+
+ /* Get a response */
+ reply_len = wait_reply (d, buf, sizeof (buf));
+
+ /* Parse the response into a result structure */
+ result = qcdm_cmd_status_snapshot_result (buf, reply_len, &error);
+ g_assert (result);
+
+ g_print ("\n");
+
+ n8 = 0;
+ qcdm_result_get_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_BAND_CLASS, &n8);
+ g_message ("%s: Band Class: %s", __func__, band_class_to_string (n8));
+
+ n8 = 0;
+ qcdm_result_get_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_BASE_STATION_PREV, &n8);
+ g_message ("%s: Base station P_REV: %s", __func__, prev_to_string (n8));
+
+ n8 = 0;
+ qcdm_result_get_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_MOBILE_PREV, &n8);
+ g_message ("%s: Mobile P_REV: %s", __func__, prev_to_string (n8));
+
+ n8 = 0;
+ qcdm_result_get_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_PREV_IN_USE, &n8);
+ g_message ("%s: P_REV in-use: %s", __func__, prev_to_string (n8));
+
+ n8 = 0;
+ qcdm_result_get_uint8 (result, QCDM_CMD_STATUS_SNAPSHOT_ITEM_STATE, &n8);
+ g_message ("%s: State: %d (%s)", __func__, n8, status_snapshot_state_to_string (n8));
+
+ qcdm_result_unref (result);
+}
+
+void
test_com_pilot_sets (void *f, void *data)
{
TestComData *d = data;
@@ -802,6 +962,9 @@ test_com_cm_subsys_state_info (void *f, void *data)
case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_WCDMA:
detail = "WCDMA";
break;
+ case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_LTE:
+ detail = "LTE";
+ break;
default:
detail = "unknown";
break;
@@ -1091,6 +1254,108 @@ test_com_hdr_subsys_state_info (void *f, void *data)
}
void
+test_com_ext_logmask (void *f, void *data)
+{
+ TestComData *d = data;
+ gboolean success;
+ GError *error = NULL;
+ char buf[520];
+ gint len;
+ QCDMResult *result;
+ gsize reply_len;
+ GSList *items = NULL;
+ guint32 maxlog = 0;
+
+ /* First get # of items the device supports */
+ len = qcdm_cmd_ext_logmask_new (buf, sizeof (buf), NULL, 0, NULL);
+
+ /* Send the command */
+ success = send_command (d, buf, len);
+ g_assert (success);
+
+ /* Get a response */
+ reply_len = wait_reply (d, buf, sizeof (buf));
+
+ g_print ("\n");
+
+ /* Parse the response into a result structure */
+ result = qcdm_cmd_ext_logmask_result (buf, reply_len, &error);
+ g_assert (result);
+
+ qcdm_result_get_uint32 (result, QCDM_CMD_EXT_LOGMASK_ITEM_MAX_ITEMS, &maxlog);
+ g_message ("%s: Max # Log Items: %u (0x%X)", __func__, maxlog, maxlog);
+
+ qcdm_result_unref (result);
+
+ /* Now enable some log items */
+ items = g_slist_append (items, GUINT_TO_POINTER (0x002C));
+ items = g_slist_append (items, GUINT_TO_POINTER (0x002E));
+ len = qcdm_cmd_ext_logmask_new (buf, sizeof (buf), items, (guint16) maxlog, NULL);
+ g_slist_free (items);
+
+ /* Send the command */
+ success = send_command (d, buf, len);
+ g_assert (success);
+
+ /* Get a response */
+ reply_len = wait_reply (d, buf, sizeof (buf));
+
+ g_print ("\n");
+
+ /* Parse the response into a result structure */
+ result = qcdm_cmd_ext_logmask_result (buf, reply_len, &error);
+ g_assert (result);
+
+ qcdm_result_unref (result);
+
+ /* Wait for a log packet */
+ reply_len = wait_reply (d, buf, sizeof (buf));
+}
+
+void
+test_com_event_report (void *f, void *data)
+{
+ TestComData *d = data;
+ gboolean success;
+ GError *error = NULL;
+ char buf[520];
+ gint len;
+ QCDMResult *result;
+ gsize reply_len;
+
+ /* Turn event reporting on */
+ len = qcdm_cmd_event_report_new (buf, sizeof (buf), TRUE, NULL);
+
+ /* Send the command */
+ success = send_command (d, buf, len);
+ g_assert (success);
+
+ /* Get a response */
+ reply_len = wait_reply (d, buf, sizeof (buf));
+
+ g_print ("\n");
+
+ /* Parse the response into a result structure */
+ result = qcdm_cmd_event_report_result (buf, reply_len, &error);
+ g_assert (result);
+
+ qcdm_result_unref (result);
+
+ /* Wait for an event */
+ reply_len = wait_reply (d, buf, sizeof (buf));
+
+ /* Turn event reporting off */
+ len = qcdm_cmd_event_report_new (buf, sizeof (buf), FALSE, NULL);
+
+ /* Send the command */
+ success = send_command (d, buf, len);
+ g_assert (success);
+
+ /* Get a response */
+ reply_len = wait_reply (d, buf, sizeof (buf));
+}
+
+void
test_com_zte_subsys_status (void *f, void *data)
{
TestComData *d = data;
diff --git a/libqcdm/tests/test-qcdm-com.h b/libqcdm/tests/test-qcdm-com.h
index 3cf7c4f..76075e5 100644
--- a/libqcdm/tests/test-qcdm-com.h
+++ b/libqcdm/tests/test-qcdm-com.h
@@ -33,16 +33,24 @@ void test_com_read_roam_pref (void *f, void *data);
void test_com_read_mode_pref (void *f, void *data);
+void test_com_read_hdr_rev_pref (void *f, void *data);
+
void test_com_status (void *f, void *data);
void test_com_sw_version (void *f, void *data);
+void test_com_status_snapshot (void *f, void *data);
+
void test_com_pilot_sets (void *f, void *data);
void test_com_cm_subsys_state_info (void *f, void *data);
void test_com_hdr_subsys_state_info (void *f, void *data);
+void test_com_ext_logmask (void *f, void *data);
+
+void test_com_event_report (void *f, void *data);
+
void test_com_zte_subsys_status (void *f, void *data);
void test_com_nw_subsys_modem_snapshot_cdma (void *f, void *data);
diff --git a/libqcdm/tests/test-qcdm-utils.c b/libqcdm/tests/test-qcdm-utils.c
index 27ec8d6..04807c1 100644
--- a/libqcdm/tests/test-qcdm-utils.c
+++ b/libqcdm/tests/test-qcdm-utils.c
@@ -84,3 +84,23 @@ test_utils_encapsulate_buffer (void *f, void *data)
g_assert (memcmp (outbuf, encap_outbuf, encap_len) == 0);
}
+static const char cns_inbuf[] = {
+ 0x00, 0x0a, 0x6b, 0x74, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e
+};
+
+void
+test_utils_decapsulate_sierra_cns (void *f, void *data)
+{
+ gboolean success;
+ char outbuf[512];
+ gsize decap_len = 0;
+ gsize used = 0;
+ gboolean more = FALSE;
+
+ success = dm_decapsulate_buffer (cns_inbuf, sizeof (cns_inbuf),
+ outbuf, sizeof (outbuf),
+ &decap_len, &used, &more);
+ g_assert (success == FALSE);
+}
+
diff --git a/libqcdm/tests/test-qcdm-utils.h b/libqcdm/tests/test-qcdm-utils.h
index 8038666..65a9944 100644
--- a/libqcdm/tests/test-qcdm-utils.h
+++ b/libqcdm/tests/test-qcdm-utils.h
@@ -22,5 +22,7 @@ void test_utils_decapsulate_buffer (void *f, void *data);
void test_utils_encapsulate_buffer (void *f, void *data);
+void test_utils_decapsulate_sierra_cns (void *f, void *data);
+
#endif /* TEST_QCDM_UTILS_H */
diff --git a/libqcdm/tests/test-qcdm.c b/libqcdm/tests/test-qcdm.c
index a58780e..946fb67 100644
--- a/libqcdm/tests/test-qcdm.c
+++ b/libqcdm/tests/test-qcdm.c
@@ -28,7 +28,11 @@ typedef struct {
gpointer com_data;
} TestData;
+#if GLIB_CHECK_VERSION(2,25,12)
+typedef GTestFixtureFunc TCFunc;
+#else
typedef void (*TCFunc)(void);
+#endif
#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL)
@@ -85,6 +89,7 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_escape_unescape, NULL));
g_test_suite_add (suite, TESTCASE (test_utils_decapsulate_buffer, NULL));
g_test_suite_add (suite, TESTCASE (test_utils_encapsulate_buffer, NULL));
+ g_test_suite_add (suite, TESTCASE (test_utils_decapsulate_sierra_cns, NULL));
g_test_suite_add (suite, TESTCASE (test_result_string, NULL));
g_test_suite_add (suite, TESTCASE (test_result_uint32, NULL));
g_test_suite_add (suite, TESTCASE (test_result_uint8, NULL));
@@ -97,11 +102,15 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_com_mdn, data->com_data));
g_test_suite_add (suite, TESTCASE (test_com_read_roam_pref, data->com_data));
g_test_suite_add (suite, TESTCASE (test_com_read_mode_pref, data->com_data));
+ g_test_suite_add (suite, TESTCASE (test_com_read_hdr_rev_pref, data->com_data));
g_test_suite_add (suite, TESTCASE (test_com_status, data->com_data));
g_test_suite_add (suite, TESTCASE (test_com_sw_version, data->com_data));
+ g_test_suite_add (suite, TESTCASE (test_com_status_snapshot, data->com_data));
g_test_suite_add (suite, TESTCASE (test_com_pilot_sets, data->com_data));
g_test_suite_add (suite, TESTCASE (test_com_cm_subsys_state_info, data->com_data));
g_test_suite_add (suite, TESTCASE (test_com_hdr_subsys_state_info, data->com_data));
+ g_test_suite_add (suite, TESTCASE (test_com_ext_logmask, data->com_data));
+ g_test_suite_add (suite, TESTCASE (test_com_event_report, data->com_data));
g_test_suite_add (suite, TESTCASE (test_com_zte_subsys_status, data->com_data));
g_test_suite_add (suite, TESTCASE (test_com_nw_subsys_modem_snapshot_cdma, data->com_data));
}
diff --git a/marshallers/Makefile.am b/marshallers/Makefile.am
index 11ce370..0d8d8f7 100644
--- a/marshallers/Makefile.am
+++ b/marshallers/Makefile.am
@@ -13,9 +13,9 @@ libmarshallers_la_CPPFLAGS = $(MM_CFLAGS)
libmarshallers_la_LIBADD = $(MM_LIBS)
mm-marshal.h: mm-marshal.list
- $(GLIB_GENMARSHAL) $< --prefix=mm_marshal --header > $@
+ $(AM_V_GEN) $(GLIB_GENMARSHAL) $< --prefix=mm_marshal --header > $@
mm-marshal.c: mm-marshal.list
- $(GLIB_GENMARSHAL) $< --prefix=mm_marshal --body > $@
+ $(AM_V_GEN) $(GLIB_GENMARSHAL) $< --prefix=mm_marshal --body > $@
mm-marshal-main.c: mm-marshal.c mm-marshal.h
diff --git a/marshallers/mm-marshal.list b/marshallers/mm-marshal.list
index c209bbb..81fcadb 100644
--- a/marshallers/mm-marshal.list
+++ b/marshallers/mm-marshal.list
@@ -6,4 +6,5 @@ VOID:UINT,UINT
VOID:UINT,UINT,UINT
VOID:STRING,BOXED
VOID:POINTER,UINT
+VOID:STRING,BOXED,BOXED
diff --git a/plugins/77-mm-ericsson-mbm.rules b/plugins/77-mm-ericsson-mbm.rules
index 8804036..51cc06f 100644
--- a/plugins/77-mm-ericsson-mbm.rules
+++ b/plugins/77-mm-ericsson-mbm.rules
@@ -17,18 +17,30 @@ ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1906", ENV{ID_MM_ERICSSON_MBM}="1"
ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="190a", ENV{ID_MM_ERICSSON_MBM}="1"
ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1909", ENV{ID_MM_ERICSSON_MBM}="1"
+# Ericsson F3307 R2
+ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1914", ENV{ID_MM_ERICSSON_MBM}="1"
+
# Ericsson C3607w
ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1049", ENV{ID_MM_ERICSSON_MBM}="1"
# Ericsson C3607w v2
ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="190b", ENV{ID_MM_ERICSSON_MBM}="1"
+# Ericsson F5521gw
+ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="190d", ENV{ID_MM_ERICSSON_MBM}="1"
+
# Sony-Ericsson MD300
ATTRS{idVendor}=="0fce", ATTRS{idProduct}=="d0cf", ENV{ID_MM_ERICSSON_MBM}="1"
# Sony-Ericsson MD400
ATTRS{idVendor}=="0fce", ATTRS{idProduct}=="d0e1", ENV{ID_MM_ERICSSON_MBM}="1"
+# Sony-Ericsson MD400G
+ATTRS{idVendor}=="0fce", ATTRS{idProduct}=="d103", ENV{ID_MM_ERICSSON_MBM}="1"
+
+# Dell 5550
+ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818d", ENV{ID_MM_ERICSSON_MBM}="1"
+
# Dell 5530 HSDPA
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8147", ENV{ID_MM_ERICSSON_MBM}="1"
@@ -40,6 +52,18 @@ ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8184", ENV{ID_MM_ERICSSON_MBM}="1"
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818b", ENV{ID_MM_ERICSSON_MBM}="1"
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818c", ENV{ID_MM_ERICSSON_MBM}="1"
+# HP hs2330 Mobile Broadband Module
+ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="271d", ENV{ID_MM_ERICSSON_MBM}="1"
+
+# HP hs2320 Mobile Broadband Module
+ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="261d", ENV{ID_MM_ERICSSON_MBM}="1"
+
+# HP lc2000 Mobile Broadband Module
+ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="301d", ENV{ID_MM_ERICSSON_MBM}="1"
+
+# HP lc2010 Mobile Broadband Module
+ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="2f1d", ENV{ID_MM_ERICSSON_MBM}="1"
+
# Toshiba
ATTRS{idVendor}=="0930", ATTRS{idProduct}=="130b", ENV{ID_MM_ERICSSON_MBM}="1"
@@ -47,5 +71,14 @@ ATTRS{idVendor}=="0930", ATTRS{idProduct}=="130b", ENV{ID_MM_ERICSSON_MBM}="1"
ATTRS{idVendor}=="0930", ATTRS{idProduct}=="130c", ENV{ID_MM_ERICSSON_MBM}="1"
ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1311", ENV{ID_MM_ERICSSON_MBM}="1"
+# Toshiba F3307
+ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1315", ENV{ID_MM_ERICSSON_MBM}="1"
+ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1316", ENV{ID_MM_ERICSSON_MBM}="1"
+ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1317", ENV{ID_MM_ERICSSON_MBM}="1"
+
+# Toshiba F5521gw
+ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1313", ENV{ID_MM_ERICSSON_MBM}="1"
+ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1314", ENV{ID_MM_ERICSSON_MBM}="1"
+
LABEL="mm_mbm_end"
diff --git a/plugins/77-mm-x22x-port-types.rules b/plugins/77-mm-x22x-port-types.rules
new file mode 100644
index 0000000..0f870a4
--- /dev/null
+++ b/plugins/77-mm-x22x-port-types.rules
@@ -0,0 +1,30 @@
+# do not edit this file, it will be overwritten on update
+
+# Alcatel One Touch X220D
+#
+# These values were scraped from the X220D's Windows .inf files. jrdmdm.inf
+# lists the actual command and data (ie PPP) ports, while jrdser.inf lists the
+# aux ports that may be either AT-capable or not but cannot be used for PPP.
+
+
+ACTION!="add|change", GOTO="mm_x22x_port_types_end"
+SUBSYSTEM!="tty", GOTO="mm_x22x_port_types_end"
+
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="1bbb", GOTO="mm_x22x_vendorcheck"
+GOTO="mm_x22x_port_types_end"
+
+LABEL="mm_x22x_vendorcheck"
+SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
+
+ATTRS{idProduct}=="0017", ENV{.MM_USBIFNUM}=="05", ENV{ID_MM_X22X_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0017", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_X22X_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="0017", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_X22X_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="0017", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_X22X_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="0017", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_X22X_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="0017", ENV{ID_MM_X22X_TAGGED}="1"
+
+GOTO="mm_x22x_port_types_end"
+
+
+LABEL="mm_x22x_port_types_end"
+
diff --git a/plugins/77-mm-zte-port-types.rules b/plugins/77-mm-zte-port-types.rules
index 9d64aa9..072154c 100644
--- a/plugins/77-mm-zte-port-types.rules
+++ b/plugins/77-mm-zte-port-types.rules
@@ -78,6 +78,9 @@ ATTRS{idProduct}=="0033", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}=
ATTRS{idProduct}=="0037", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
ATTRS{idProduct}=="0037", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="0039", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0039", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
ATTRS{idProduct}=="0042", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
ATTRS{idProduct}=="0042", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
@@ -93,9 +96,15 @@ ATTRS{idProduct}=="0049", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_AUX}=
ATTRS{idProduct}=="0052", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
ATTRS{idProduct}=="0052", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="0054", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0054", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
ATTRS{idProduct}=="0055", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
ATTRS{idProduct}=="0055", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="0057", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0057", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
@@ -108,8 +117,56 @@ ATTRS{idProduct}=="0064", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_ZTE_PORT_TYPE_AUX}=
ATTRS{idProduct}=="0066", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
ATTRS{idProduct}=="0066", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="0082", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0082", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0104", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0104", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0108", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0108", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0113", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0113", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0117", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0117", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0118", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0118", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0121", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0121", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0123", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0123", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0124", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0124", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0125", ENV{.MM_USBIFNUM}=="05", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0125", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0126", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0126", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0128", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0128", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="1007", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="1007", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="1008", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="1008", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="1010", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="1010", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
ATTRS{idProduct}=="2002", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
ATTRS{idProduct}=="2002", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="2003", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="2003", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
LABEL="mm_zte_port_types_end"
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 8192653..dd58b94 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -1,3 +1,24 @@
+
+##########################
+# Icera-specific support #
+##########################
+
+noinst_LTLIBRARIES = libicera-utils.la
+
+libicera_utils_la_SOURCES = \
+ mm-modem-icera.c \
+ mm-modem-icera.h
+
+libicera_utils_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libicera_utils_la_LIBADD = \
+ $(GUDEV_LDFLAGS)
+
+########################################
+
pkglib_LTLIBRARIES = \
libmm-plugin-generic.la \
libmm-plugin-moto-c.la \
@@ -12,7 +33,9 @@ pkglib_LTLIBRARIES = \
libmm-plugin-mbm.la \
libmm-plugin-longcheer.la \
libmm-plugin-anydata.la \
- libmm-plugin-simtech.la
+ libmm-plugin-simtech.la \
+ libmm-plugin-x22x.la \
+ libmm-plugin-linktop.la
# Generic
@@ -95,8 +118,8 @@ libmm_plugin_hso_la_SOURCES = \
mm-modem-hso.c \
mm-modem-hso.h
-mm-modem-gsm-hso-glue.h: $(top_srcdir)/introspection/mm-modem-gsm-hso.xml
- dbus-binding-tool --prefix=mm_modem_gsm_hso --mode=glib-server --output=$@ $<
+mm-modem-gsm-hso-glue.h: $(top_srcdir)/introspection/org.freedesktop.ModemManager.Modem.Gsm.Hso.xml
+ $(AM_V_GEN) dbus-binding-tool --prefix=mm_modem_gsm_hso --mode=glib-server --output=$@ $<
libmm_plugin_hso_la_CPPFLAGS = \
$(MM_CFLAGS) \
@@ -177,7 +200,8 @@ libmm_plugin_novatel_la_SOURCES = \
libmm_plugin_novatel_la_CPPFLAGS = \
$(MM_CFLAGS) \
$(GUDEV_CFLAGS) \
- -I$(top_srcdir)/src
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)
libmm_plugin_novatel_la_LDFLAGS = \
$(GUDEV_LDFLAGS) \
@@ -217,6 +241,7 @@ libmm_plugin_zte_la_CPPFLAGS = \
libmm_plugin_zte_la_LDFLAGS = \
$(GUDEV_LDFLAGS) \
+ $(builddir)/libicera-utils.la \
-module \
-avoid-version
@@ -274,13 +299,49 @@ libmm_plugin_simtech_la_LDFLAGS = \
-module \
-avoid-version
+# Alcatel/TCT/JRD x220D and possibly others
+
+libmm_plugin_x22x_la_SOURCES = \
+ mm-plugin-x22x.c \
+ mm-plugin-x22x.h \
+ mm-modem-x22x-gsm.c \
+ mm-modem-x22x-gsm.h
+
+libmm_plugin_x22x_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_x22x_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
+
+# Linktop
+
+libmm_plugin_linktop_la_SOURCES = \
+ mm-plugin-linktop.c \
+ mm-plugin-linktop.h \
+ mm-modem-linktop.c \
+ mm-modem-linktop.h
+
+libmm_plugin_linktop_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_linktop_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
udevrulesdir = $(UDEV_BASE_DIR)/rules.d
udevrules_DATA = \
77-mm-ericsson-mbm.rules \
77-mm-zte-port-types.rules \
77-mm-longcheer-port-types.rules \
- 77-mm-simtech-port-types.rules
+ 77-mm-simtech-port-types.rules \
+ 77-mm-x22x-port-types.rules
BUILT_SOURCES = \
mm-modem-gsm-hso-glue.h
diff --git a/plugins/mm-modem-anydata-cdma.c b/plugins/mm-modem-anydata-cdma.c
index c7cca46..0e7e65c 100644
--- a/plugins/mm-modem-anydata-cdma.c
+++ b/plugins/mm-modem-anydata-cdma.c
@@ -28,6 +28,7 @@
#include "mm-callback-info.h"
#include "mm-serial-port.h"
#include "mm-serial-parsers.h"
+#include "mm-log.h"
static void modem_init (MMModem *modem_class);
@@ -39,7 +40,9 @@ mm_modem_anydata_cdma_new (const char *device,
const char *driver,
const char *plugin,
gboolean evdo_rev0,
- gboolean evdo_revA)
+ gboolean evdo_revA,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -52,6 +55,8 @@ mm_modem_anydata_cdma_new (const char *device,
MM_GENERIC_CDMA_EVDO_REV0, evdo_rev0,
MM_GENERIC_CDMA_EVDO_REVA, evdo_revA,
MM_GENERIC_CDMA_REGISTRATION_TRY_CSS, FALSE,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
@@ -136,7 +141,7 @@ evdo_state_done (MMAtSerialPort *port,
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
if (!r) {
/* Parse error; warn about it and assume EVDO is not available */
- g_warning ("AnyDATA(%s): *HSTATE parse regex creation failed.", __func__);
+ mm_warn ("ANYDATA: *HSTATE parse regex creation failed.");
goto done;
}
@@ -163,7 +168,7 @@ evdo_state_done (MMAtSerialPort *port,
reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
break;
default:
- g_message ("ANYDATA: unknown *STATE (%d); assuming no service.", val);
+ mm_warn ("ANYDATA: unknown *STATE (%d); assuming no service.", val);
/* fall through */
case 0: /* NO SERVICE */
case 1: /* ACQUISITION */
@@ -202,7 +207,7 @@ state_done (MMAtSerialPort *port,
r = g_regex_new ("\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*([^,\\)]*)\\s*,.*",
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
if (!r) {
- g_warning ("AnyDATA(%s): *STATE parse regex creation failed.", __func__);
+ mm_warn ("ANYDATA: *STATE parse regex creation failed.");
mm_callback_info_schedule (info);
return;
}
@@ -231,7 +236,7 @@ state_done (MMAtSerialPort *port,
reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
break;
default:
- g_warning ("ANYDATA: unknown *STATE (%d); assuming no service.", val);
+ mm_warn ("ANYDATA: unknown *STATE (%d); assuming no service.", val);
/* fall through */
case 0: /* NO SERVICE */
break;
@@ -268,6 +273,24 @@ query_registration_state (MMGenericCdma *cdma,
/*****************************************************************************/
+static void
+reset (MMModem *modem,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
+
+ info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
+
+ /* Ensure we have a usable port to use for the command */
+ port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (modem), &info->error);
+ if (port)
+ mm_at_serial_port_queue_command (port, "*RESET", 3, NULL, NULL);
+
+ mm_callback_info_schedule (info);
+}
+
static gboolean
grab_port (MMModem *modem,
const char *subsys,
@@ -329,6 +352,7 @@ static void
modem_init (MMModem *modem_class)
{
modem_class->grab_port = grab_port;
+ modem_class->reset = reset;
}
static void
diff --git a/plugins/mm-modem-anydata-cdma.h b/plugins/mm-modem-anydata-cdma.h
index d2695d5..5a9fc4b 100644
--- a/plugins/mm-modem-anydata-cdma.h
+++ b/plugins/mm-modem-anydata-cdma.h
@@ -40,6 +40,8 @@ MMModem *mm_modem_anydata_cdma_new (const char *device,
const char *driver,
const char *plugin,
gboolean evdo_rev0,
- gboolean evdo_revA);
+ gboolean evdo_revA,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_ANYDATA_CDMA_H */
diff --git a/plugins/mm-modem-gobi-gsm.c b/plugins/mm-modem-gobi-gsm.c
index 3b9e9ec..7e2fa4c 100644
--- a/plugins/mm-modem-gobi-gsm.c
+++ b/plugins/mm-modem-gobi-gsm.c
@@ -36,7 +36,9 @@ G_DEFINE_TYPE_EXTENDED (MMModemGobiGsm, mm_modem_gobi_gsm, MM_TYPE_GENERIC_GSM,
MMModem *
mm_modem_gobi_gsm_new (const char *device,
const char *driver,
- const char *plugin)
+ const char *plugin,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -46,6 +48,8 @@ mm_modem_gobi_gsm_new (const char *device,
MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
diff --git a/plugins/mm-modem-gobi-gsm.h b/plugins/mm-modem-gobi-gsm.h
index 4bd262f..b1af164 100644
--- a/plugins/mm-modem-gobi-gsm.h
+++ b/plugins/mm-modem-gobi-gsm.h
@@ -38,6 +38,8 @@ GType mm_modem_gobi_gsm_get_type (void);
MMModem *mm_modem_gobi_gsm_new (const char *device,
const char *driver,
- const char *plugin_name);
+ const char *plugin_name,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_GOBI_GSM_H */
diff --git a/plugins/mm-modem-hso.c b/plugins/mm-modem-hso.c
index 1fd4633..ff0264a 100644
--- a/plugins/mm-modem-hso.c
+++ b/plugins/mm-modem-hso.c
@@ -74,7 +74,9 @@ typedef struct {
MMModem *
mm_modem_hso_new (const char *device,
const char *driver,
- const char *plugin)
+ const char *plugin,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -85,6 +87,8 @@ mm_modem_hso_new (const char *device,
MM_MODEM_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
MM_MODEM_IP_METHOD, MM_MODEM_IP_METHOD_STATIC,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
@@ -427,7 +431,7 @@ unsolicited_disable_done (MMModem *modem,
}
/* Otherwise, kill any existing connection */
- if (mm_generic_gsm_get_cid (MM_GENERIC_GSM (modem)) >= 0)
+ if (hso_get_cid (MM_MODEM_HSO (modem)) >= 0)
hso_call_control (MM_MODEM_HSO (modem), FALSE, TRUE, disable_done, info);
else
disable_done (modem, NULL, info);
diff --git a/plugins/mm-modem-hso.h b/plugins/mm-modem-hso.h
index e2d7623..7e79886 100644
--- a/plugins/mm-modem-hso.h
+++ b/plugins/mm-modem-hso.h
@@ -38,7 +38,9 @@ GType mm_modem_hso_get_type (void);
MMModem *mm_modem_hso_new (const char *device,
const char *driver,
- const char *plugin);
+ const char *plugin,
+ guint32 vendor,
+ guint32 product);
void mm_hso_modem_authenticate (MMModemHso *self,
const char *username,
diff --git a/plugins/mm-modem-huawei-cdma.c b/plugins/mm-modem-huawei-cdma.c
index 523578f..3aec470 100644
--- a/plugins/mm-modem-huawei-cdma.c
+++ b/plugins/mm-modem-huawei-cdma.c
@@ -27,6 +27,7 @@
#include "mm-callback-info.h"
#include "mm-serial-port.h"
#include "mm-serial-parsers.h"
+#include "mm-log.h"
static void modem_init (MMModem *modem_class);
@@ -39,7 +40,9 @@ mm_modem_huawei_cdma_new (const char *device,
const char *driver,
const char *plugin,
gboolean evdo_rev0,
- gboolean evdo_revA)
+ gboolean evdo_revA,
+ guint32 vendor,
+ guint32 product)
{
gboolean try_css = TRUE;
@@ -61,6 +64,8 @@ mm_modem_huawei_cdma_new (const char *device,
MM_GENERIC_CDMA_EVDO_REV0, evdo_rev0,
MM_GENERIC_CDMA_EVDO_REVA, evdo_revA,
MM_GENERIC_CDMA_REGISTRATION_TRY_CSS, try_css,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
@@ -75,7 +80,7 @@ parse_quality (const char *str, const char *detail)
quality = strtol (str, NULL, 10);
if (errno == 0) {
quality = CLAMP (quality, 0, 100);
- g_debug ("%s: %ld", detail, quality);
+ mm_dbg ("%s: %ld", detail, quality);
return (gint) quality;
}
return -1;
@@ -173,7 +178,7 @@ sysinfo_done (MMAtSerialPort *port,
r = g_regex_new ("\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)",
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
if (!r) {
- g_warning ("Huawei(%s): ^SYSINFO parse regex creation failed.", __func__);
+ mm_warn ("Huawei: ^SYSINFO parse regex creation failed.");
goto done;
}
@@ -214,7 +219,7 @@ sysinfo_done (MMAtSerialPort *port,
mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state);
}
} else
- g_warning ("Huawei(%s): failed to parse ^SYSINFO response.", __func__);
+ mm_warn ("Huawei: failed to parse ^SYSINFO response.");
g_match_info_free (match_info);
g_regex_unref (r);
diff --git a/plugins/mm-modem-huawei-cdma.h b/plugins/mm-modem-huawei-cdma.h
index 738f2d9..88b425c 100644
--- a/plugins/mm-modem-huawei-cdma.h
+++ b/plugins/mm-modem-huawei-cdma.h
@@ -40,6 +40,8 @@ MMModem *mm_modem_huawei_cdma_new (const char *device,
const char *driver,
const char *plugin,
gboolean evdo_rev0,
- gboolean evdo_revA);
+ gboolean evdo_revA,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_HUAWEI_CDMA_H */
diff --git a/plugins/mm-modem-huawei-gsm.c b/plugins/mm-modem-huawei-gsm.c
index 5123e7f..3fc9ae2 100644
--- a/plugins/mm-modem-huawei-gsm.c
+++ b/plugins/mm-modem-huawei-gsm.c
@@ -29,6 +29,7 @@
#include "mm-callback-info.h"
#include "mm-at-serial-port.h"
#include "mm-serial-parsers.h"
+#include "mm-log.h"
static void modem_init (MMModem *modem_class);
static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class);
@@ -50,7 +51,9 @@ typedef struct {
MMModem *
mm_modem_huawei_gsm_new (const char *device,
const char *driver,
- const char *plugin)
+ const char *plugin,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -60,6 +63,8 @@ mm_modem_huawei_gsm_new (const char *device,
MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
@@ -362,6 +367,35 @@ get_band (MMModemGsmNetwork *modem,
mm_at_serial_port_queue_command (port, "AT^SYSCFG?", 3, get_band_done, info);
}
+static MMModemGsmAccessTech
+huawei_sysinfo_to_act (int huawei)
+{
+ switch (huawei) {
+ case 1:
+ return MM_MODEM_GSM_ACCESS_TECH_GSM;
+ case 2:
+ return MM_MODEM_GSM_ACCESS_TECH_GPRS;
+ case 3:
+ return MM_MODEM_GSM_ACCESS_TECH_EDGE;
+ case 4:
+ return MM_MODEM_GSM_ACCESS_TECH_UMTS;
+ case 5:
+ return MM_MODEM_GSM_ACCESS_TECH_HSDPA;
+ case 6:
+ return MM_MODEM_GSM_ACCESS_TECH_HSUPA;
+ case 7:
+ return MM_MODEM_GSM_ACCESS_TECH_HSPA;
+ case 9:
+ return MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS;
+ case 8:
+ /* TD-SCDMA */
+ default:
+ break;
+ }
+
+ return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+}
+
static void
get_act_request_done (MMAtSerialPort *port,
GString *response,
@@ -404,22 +438,8 @@ get_act_request_done (MMAtSerialPort *port,
if (srv_stat != 0) {
/* Valid service */
str = g_match_info_fetch (match_info, 7);
- if (str && strlen (str)) {
- if (str[0] == '1')
- act = MM_MODEM_GSM_ACCESS_TECH_GSM;
- else if (str[0] == '2')
- act = MM_MODEM_GSM_ACCESS_TECH_GPRS;
- else if (str[0] == '3')
- act = MM_MODEM_GSM_ACCESS_TECH_EDGE;
- else if (str[0] == '4')
- act = MM_MODEM_GSM_ACCESS_TECH_UMTS;
- else if (str[0] == '5')
- act = MM_MODEM_GSM_ACCESS_TECH_HSDPA;
- else if (str[0] == '6')
- act = MM_MODEM_GSM_ACCESS_TECH_HSUPA;
- else if (str[0] == '7')
- act = MM_MODEM_GSM_ACCESS_TECH_HSPA;
- }
+ if (str && strlen (str))
+ act = huawei_sysinfo_to_act (atoi (str));
g_free (str);
}
@@ -514,7 +534,7 @@ send_huawei_cpin_done (MMAtSerialPort *port,
else if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PIN2))
num = 5;
else {
- g_debug ("%s: unhandled pin type '%s'", __func__, pin_type);
+ mm_dbg ("unhandled pin type '%s'", pin_type);
info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Unhandled PIN type");
}
@@ -556,7 +576,7 @@ get_unlock_retries (MMModemGsmCard *modem,
char *command;
MMCallbackInfo *info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- g_debug ("%s: pin type '%s'", __func__, pin_type);
+ mm_dbg ("pin type '%s'", pin_type);
/* Ensure we have a usable port to use for the command */
port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error);
@@ -622,40 +642,30 @@ handle_mode_change (MMAtSerialPort *port,
MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
char *str;
int a;
- int b;
str = g_match_info_fetch (match_info, 1);
a = atoi (str);
g_free (str);
str = g_match_info_fetch (match_info, 2);
- b = atoi (str);
+ act = huawei_sysinfo_to_act (atoi (str));
g_free (str);
if (a == 3) { /* GSM/GPRS mode */
- if (b == 1)
- act = MM_MODEM_GSM_ACCESS_TECH_GSM;
- else if (b == 2)
- act = MM_MODEM_GSM_ACCESS_TECH_GPRS;
- else if (b == 3)
- act = MM_MODEM_GSM_ACCESS_TECH_EDGE;
+ if (act > MM_MODEM_GSM_ACCESS_TECH_EDGE)
+ act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
} else if (a == 5) { /* WCDMA mode */
- if (b == 4)
- act = MM_MODEM_GSM_ACCESS_TECH_UMTS;
- else if (b == 5)
- act = MM_MODEM_GSM_ACCESS_TECH_HSDPA;
- else if (b == 6)
- act = MM_MODEM_GSM_ACCESS_TECH_HSUPA;
- else if (b == 7)
- act = MM_MODEM_GSM_ACCESS_TECH_HSPA;
+ if (act < MM_MODEM_GSM_ACCESS_TECH_UMTS)
+ act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
} else if (a == 0)
act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
else {
- g_warning ("Couldn't parse mode change value: '%s'", str);
+ mm_warn ("Couldn't parse mode change value: '%s'", str);
return;
}
- g_debug ("Access Technology: %d", act);
+ mm_dbg ("Access Technology: %d", act);
+
mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (self), act);
}
@@ -669,8 +679,8 @@ handle_status_change (MMAtSerialPort *port,
str = g_match_info_fetch (match_info, 1);
if (sscanf (str, "%x,%x,%x,%x,%x,%x,%x", &n1, &n2, &n3, &n4, &n5, &n6, &n7)) {
- g_debug ("Duration: %d Up: %d Kbps Down: %d Kbps Total: %d Total: %d\n",
- n1, n2 * 8 / 1000, n3 * 8 / 1000, n4 / 1024, n5 / 1024);
+ mm_dbg ("Duration: %d Up: %d Kbps Down: %d Kbps Total: %d Total: %d\n",
+ n1, n2 * 8 / 1000, n3 * 8 / 1000, n4 / 1024, n5 / 1024);
}
g_free (str);
}
diff --git a/plugins/mm-modem-huawei-gsm.h b/plugins/mm-modem-huawei-gsm.h
index 9c2ec34..05f1f29 100644
--- a/plugins/mm-modem-huawei-gsm.h
+++ b/plugins/mm-modem-huawei-gsm.h
@@ -38,6 +38,8 @@ GType mm_modem_huawei_gsm_get_type (void);
MMModem *mm_modem_huawei_gsm_new (const char *device,
const char *driver,
- const char *plugin);
+ const char *plugin,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_HUAWEI_GSM_H */
diff --git a/plugins/mm-modem-icera.c b/plugins/mm-modem-icera.c
new file mode 100644
index 0000000..3f71c5b
--- /dev/null
+++ b/plugins/mm-modem-icera.c
@@ -0,0 +1,794 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ */
+
+/******************************************
+ * Generic utilities for Icera-based modems
+ ******************************************/
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+
+#include "mm-modem-icera.h"
+
+#include "mm-modem.h"
+#include "mm-errors.h"
+#include "mm-callback-info.h"
+#include "mm-at-serial-port.h"
+#include "mm-generic-gsm.h"
+#include "mm-modem-helpers.h"
+#include "mm-log.h"
+
+struct _MMModemIceraPrivate {
+ /* Pending connection attempt */
+ MMCallbackInfo *connect_pending_data;
+ guint connect_pending_id;
+
+ char *username;
+ char *password;
+
+ MMModemGsmAccessTech last_act;
+};
+
+#define MM_MODEM_ICERA_GET_PRIVATE(m) (MM_MODEM_ICERA_GET_INTERFACE(m)->priv)
+
+static void
+get_allowed_mode_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ gboolean parsed = FALSE;
+
+ if (error)
+ info->error = g_error_copy (error);
+ else if (!g_str_has_prefix (response->str, "%IPSYS: ")) {
+ int a, b;
+
+ if (sscanf (response->str + 8, "%d,%d", &a, &b)) {
+ MMModemGsmAllowedMode mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+
+ switch (a) {
+ case 0:
+ mode = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY;
+ break;
+ case 1:
+ mode = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY;
+ break;
+ case 2:
+ mode = MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED;
+ break;
+ case 3:
+ mode = MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED;
+ break;
+ default:
+ break;
+ }
+
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mode), NULL);
+ parsed = TRUE;
+ }
+ }
+
+ if (!error && !parsed)
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Could not parse allowed mode results");
+
+ mm_callback_info_schedule (info);
+}
+
+void
+mm_modem_icera_get_allowed_mode (MMModemIcera *self,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
+
+ info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+ mm_at_serial_port_queue_command (port, "%IPSYS?", 3, get_allowed_mode_done, info);
+}
+
+static void
+set_allowed_mode_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ if (error)
+ info->error = g_error_copy (error);
+
+ mm_callback_info_schedule (info);
+}
+
+void
+mm_modem_icera_set_allowed_mode (MMModemIcera *self,
+ MMModemGsmAllowedMode mode,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
+ char *command;
+ int i;
+
+ info = mm_callback_info_new (MM_MODEM (self), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ switch (mode) {
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY:
+ i = 0;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY:
+ i = 1;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED:
+ i = 2;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED:
+ i = 3;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_ANY:
+ default:
+ i = 5;
+ break;
+ }
+
+ command = g_strdup_printf ("%%IPSYS=%d", i);
+ mm_at_serial_port_queue_command (port, command, 3, set_allowed_mode_done, info);
+ g_free (command);
+}
+
+static MMModemGsmAccessTech
+nwstate_to_act (const char *str)
+{
+ /* small 'g' means CS, big 'G' means PS */
+ if (!strcmp (str, "2G-GPRS"))
+ return MM_MODEM_GSM_ACCESS_TECH_GPRS;
+ else if (!strcmp (str, "2G-EDGE"))
+ return MM_MODEM_GSM_ACCESS_TECH_EDGE;
+ else if (!strcmp (str, "3G"))
+ return MM_MODEM_GSM_ACCESS_TECH_UMTS;
+ else if (!strcmp (str, "3G-HSDPA"))
+ return MM_MODEM_GSM_ACCESS_TECH_HSDPA;
+ else if (!strcmp (str, "3G-HSUPA"))
+ return MM_MODEM_GSM_ACCESS_TECH_HSUPA;
+ else if (!strcmp (str, "3G-HSDPA-HSUPA"))
+ return MM_MODEM_GSM_ACCESS_TECH_HSPA;
+
+ return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+}
+
+static void
+nwstate_changed (MMAtSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data)
+{
+ MMModemIcera *self = MM_MODEM_ICERA (user_data);
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ char *str;
+ int rssi = -1;
+
+ str = g_match_info_fetch (info, 1);
+ if (str) {
+ rssi = atoi (str);
+ rssi = CLAMP (rssi, -1, 5);
+ g_free (str);
+ }
+
+ str = g_match_info_fetch (info, 3);
+ if (str) {
+ act = nwstate_to_act (str);
+ g_free (str);
+ }
+
+ MM_MODEM_ICERA_GET_PRIVATE (self)->last_act = act;
+ mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (self), act);
+}
+
+static void
+pacsp_received (MMAtSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data)
+{
+ return;
+}
+
+static void
+get_nwstate_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (!info->error) {
+ MMModemIcera *self = MM_MODEM_ICERA (info->modem);
+ MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self);
+
+ /* The unsolicited message handler will already have run and
+ * removed the NWSTATE response, so we have to work around that.
+ */
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->last_act), NULL);
+ priv->last_act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+void
+mm_modem_icera_get_access_technology (MMModemIcera *self,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMAtSerialPort *port;
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (port, "%NWSTATE=1", 3, get_nwstate_done, info);
+}
+
+/****************************************************************/
+
+static void
+disconnect_ipdpact_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ mm_callback_info_schedule ((MMCallbackInfo *) user_data);
+}
+
+void
+mm_modem_icera_do_disconnect (MMGenericGsm *gsm,
+ gint cid,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *primary;
+ char *command;
+
+ info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data);
+
+ primary = mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
+ command = g_strdup_printf ("%%IPDPACT=%d,0", cid);
+ mm_at_serial_port_queue_command (primary, command, 3, disconnect_ipdpact_done, info);
+ g_free (command);
+}
+
+/*****************************************************************************/
+
+static void
+connect_pending_done (MMModemIcera *self)
+{
+ MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self);
+ GError *error = NULL;
+
+ if (priv->connect_pending_data) {
+ if (priv->connect_pending_data->error) {
+ error = priv->connect_pending_data->error;
+ priv->connect_pending_data->error = NULL;
+ }
+
+ /* Complete the connect */
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (self), error, priv->connect_pending_data);
+ priv->connect_pending_data = NULL;
+ }
+
+ if (priv->connect_pending_id) {
+ g_source_remove (priv->connect_pending_id);
+ priv->connect_pending_id = 0;
+ }
+}
+
+static void
+icera_disconnect_done (MMModem *modem,
+ GError *error,
+ gpointer user_data)
+{
+ mm_info ("Modem signaled disconnection from the network");
+}
+
+static void
+connection_enabled (MMAtSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data)
+{
+ MMModemIcera *self = MM_MODEM_ICERA (user_data);
+ MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self);
+ MMCallbackInfo *info = priv->connect_pending_data;
+ char *str;
+ int status, cid, tmp;
+
+ cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self));
+ if (cid < 0)
+ return;
+
+ str = g_match_info_fetch (match_info, 1);
+ g_return_if_fail (str != NULL);
+ tmp = atoi (str);
+ g_free (str);
+
+ /* Make sure the unsolicited message's CID matches the current CID */
+ if (tmp != cid)
+ return;
+
+ str = g_match_info_fetch (match_info, 2);
+ g_return_if_fail (str != NULL);
+ status = atoi (str);
+ g_free (str);
+
+ switch (status) {
+ case 0:
+ /* Disconnected */
+ if (mm_modem_get_state (MM_MODEM (self)) >= MM_MODEM_STATE_CONNECTED)
+ mm_modem_disconnect (MM_MODEM (self), icera_disconnect_done, NULL);
+ break;
+ case 1:
+ /* Connected */
+ connect_pending_done (self);
+ break;
+ case 2:
+ /* Connecting */
+ break;
+ case 3:
+ /* Call setup failure? */
+ if (info) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Call setup failed");
+ }
+ connect_pending_done (self);
+ break;
+ default:
+ mm_warn ("Unknown Icera connect status %d", status);
+ break;
+ }
+}
+
+/****************************************************************/
+
+static gint
+_get_cid (MMModemIcera *self)
+{
+ gint cid;
+
+ cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self));
+ if (cid < 0) {
+ g_warn_if_fail (cid >= 0);
+ cid = 0;
+ }
+ return cid;
+}
+
+static void
+icera_call_control (MMModemIcera *self,
+ gboolean activate,
+ MMAtSerialResponseFn callback,
+ gpointer user_data)
+{
+ char *command;
+ MMAtSerialPort *primary;
+
+ primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
+ command = g_strdup_printf ("%%IPDPACT=%d,%d", _get_cid (self), activate ? 1 : 0);
+ mm_at_serial_port_queue_command (primary, command, 3, callback, user_data);
+ g_free (command);
+}
+
+static void
+timeout_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ connect_pending_done (MM_MODEM_ICERA (user_data));
+}
+
+static gboolean
+icera_connect_timed_out (gpointer data)
+{
+ MMModemIcera *self = MM_MODEM_ICERA (data);
+ MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self);
+ MMCallbackInfo *info = priv->connect_pending_data;
+
+ priv->connect_pending_id = 0;
+
+ if (info) {
+ info->error = g_error_new_literal (MM_SERIAL_ERROR,
+ MM_SERIAL_ERROR_RESPONSE_TIMEOUT,
+ "Connection timed out");
+ }
+
+ icera_call_control (self, FALSE, timeout_done, self);
+ return FALSE;
+}
+
+static void
+icera_enabled (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ if (error) {
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), error, info);
+ } else {
+ MMModemIcera *self = MM_MODEM_ICERA (info->modem);
+ MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self);
+
+ g_warn_if_fail (priv->connect_pending_id == 0);
+ if (priv->connect_pending_id)
+ g_source_remove (priv->connect_pending_id);
+
+ priv->connect_pending_data = info;
+ priv->connect_pending_id = g_timeout_add_seconds (30, icera_connect_timed_out, self);
+ }
+}
+
+static void
+old_context_clear_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ /* Activate the PDP context and start the data session */
+ icera_call_control (MM_MODEM_ICERA (info->modem), TRUE, icera_enabled, info);
+}
+
+static void
+auth_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ if (error)
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), error, info);
+ else {
+ /* Ensure the PDP context is deactivated */
+ icera_call_control (MM_MODEM_ICERA (info->modem), FALSE, old_context_clear_done, info);
+ }
+}
+
+void
+mm_modem_icera_do_connect (MMModemIcera *self,
+ const char *number,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMModem *modem = MM_MODEM (self);
+ MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self);
+ MMCallbackInfo *info;
+ MMAtSerialPort *primary;
+ gint cid;
+ char *command;
+
+ mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE);
+
+ info = mm_callback_info_new (modem, callback, user_data);
+
+ primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
+ cid = _get_cid (self);
+
+
+ /* Both user and password are required; otherwise firmware returns an error */
+ if (!priv->username || !priv->password)
+ command = g_strdup_printf ("%%IPDPCFG=%d,0,0,\"\",\"\"", cid);
+ else {
+ command = g_strdup_printf ("%%IPDPCFG=%d,0,1,\"%s\",\"%s\"",
+ cid,
+ priv->password ? priv->password : "",
+ priv->username ? priv->username : "");
+
+ }
+
+ mm_at_serial_port_queue_command (primary, command, 3, auth_done, info);
+ g_free (command);
+}
+
+/****************************************************************/
+
+
+static void
+free_dns_array (gpointer data)
+{
+ g_array_free ((GArray *) data, TRUE);
+}
+
+static void
+ip4_config_invoke (MMCallbackInfo *info)
+{
+ MMModemIp4Fn callback = (MMModemIp4Fn) info->callback;
+
+ callback (info->modem,
+ GPOINTER_TO_UINT (mm_callback_info_get_data (info, "ip4-address")),
+ (GArray *) mm_callback_info_get_data (info, "ip4-dns"),
+ info->error, info->user_data);
+}
+
+#define IPDPADDR_TAG "%IPDPADDR: "
+
+static void
+get_ip4_config_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ char **items, **iter;
+ GArray *dns_array;
+ int i;
+ guint32 tmp;
+ gint cid;
+
+ if (error) {
+ info->error = g_error_copy (error);
+ goto out;
+ } else if (!g_str_has_prefix (response->str, IPDPADDR_TAG)) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Retrieving failed: invalid response.");
+ goto out;
+ }
+
+ cid = _get_cid (MM_MODEM_ICERA (info->modem));
+ dns_array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 2);
+
+ /* %IPDPADDR: <cid>,<ip>,<gw>,<dns1>,<dns2>[,<nbns1>,<nbns2>] */
+ items = g_strsplit (response->str + strlen (IPDPADDR_TAG), ", ", 0);
+
+ for (iter = items, i = 0; *iter; iter++, i++) {
+ if (i == 0) { /* CID */
+ long int num;
+
+ errno = 0;
+ num = strtol (*iter, NULL, 10);
+ if (errno != 0 || num < 0 || (gint) num != cid) {
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Unknown CID in IPDPADDR response ("
+ "got %d, expected %d)", (guint) num, cid);
+ break;
+ }
+ } else if (i == 1) { /* IP address */
+ if (inet_pton (AF_INET, *iter, &tmp) > 0)
+ mm_callback_info_set_data (info, "ip4-address", GUINT_TO_POINTER (tmp), NULL);
+ } else if (i == 3) { /* DNS 1 */
+ if (inet_pton (AF_INET, *iter, &tmp) > 0)
+ g_array_append_val (dns_array, tmp);
+ } else if (i == 4) { /* DNS 2 */
+ if (inet_pton (AF_INET, *iter, &tmp) > 0)
+ g_array_append_val (dns_array, tmp);
+ }
+ }
+
+ g_strfreev (items);
+ mm_callback_info_set_data (info, "ip4-dns", dns_array, free_dns_array);
+
+ out:
+ mm_callback_info_schedule (info);
+}
+
+void
+mm_modem_icera_get_ip4_config (MMModemIcera *self,
+ MMModemIp4Fn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ char *command;
+ MMAtSerialPort *primary;
+
+ info = mm_callback_info_new_full (MM_MODEM (self),
+ ip4_config_invoke,
+ G_CALLBACK (callback),
+ user_data);
+
+ primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
+ command = g_strdup_printf ("%%IPDPADDR=%d", _get_cid (self));
+ mm_at_serial_port_queue_command (primary, command, 3, get_ip4_config_done, info);
+ g_free (command);
+}
+
+/****************************************************************/
+
+static const char *
+get_string_property (GHashTable *properties, const char *name)
+{
+ GValue *value;
+
+ value = (GValue *) g_hash_table_lookup (properties, name);
+ if (value && G_VALUE_HOLDS_STRING (value))
+ return g_value_get_string (value);
+ return NULL;
+}
+
+void
+mm_modem_icera_simple_connect (MMModemIcera *self, GHashTable *properties)
+{
+ MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self);
+
+ g_free (priv->username);
+ priv->username = g_strdup (get_string_property (properties, "username"));
+ g_free (priv->password);
+ priv->password = g_strdup (get_string_property (properties, "password"));
+}
+
+/****************************************************************/
+
+void
+mm_modem_icera_register_unsolicted_handlers (MMModemIcera *self,
+ MMAtSerialPort *port)
+{
+ GRegex *regex;
+
+ /* %NWSTATE: <rssi>,<mccmnc>,<tech>,<connected>,<regulation> */
+ regex = g_regex_new ("\\r\\n%NWSTATE:\\s*(\\d+),(\\d+),([^,]*),([^,]*),(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (port, regex, nwstate_changed, self, NULL);
+ g_regex_unref (regex);
+
+ regex = g_regex_new ("\\r\\n\\+PACSP(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (port, regex, pacsp_received, self, NULL);
+ g_regex_unref (regex);
+
+ /* %IPDPACT: <cid>,<status>,0 */
+ regex = g_regex_new ("\\r\\n%IPDPACT:\\s*(\\d+),\\s*(\\d+),\\s*(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (port, regex, connection_enabled, self, NULL);
+ g_regex_unref (regex);
+}
+
+void
+mm_modem_icera_change_unsolicited_messages (MMModemIcera *self, gboolean enabled)
+{
+ MMAtSerialPort *primary;
+
+ primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
+ mm_at_serial_port_queue_command (primary, enabled ? "%NWSTATE=1" : "%NWSTATE=0", 3, NULL, NULL);
+}
+
+/****************************************************************/
+
+static void
+is_icera_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (!info->error)
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (TRUE), NULL);
+ mm_callback_info_schedule (info);
+}
+
+void
+mm_modem_icera_is_icera (MMModemIcera *self,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMAtSerialPort *port;
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (port, "%IPSYS?", 5, is_icera_done, info);
+}
+
+/****************************************************************/
+
+void
+mm_modem_icera_prepare (MMModemIcera *self)
+{
+ self->priv = g_malloc0 (sizeof (MMModemIceraPrivate));
+}
+
+void
+mm_modem_icera_cleanup (MMModemIcera *self)
+{
+ MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self);
+
+ /* Clear the pending connection if necessary */
+ connect_pending_done (self);
+
+ g_free (priv->username);
+ g_free (priv->password);
+
+ memset (priv, 0, sizeof (MMModemIceraPrivate));
+ g_free (priv);
+}
+
+static void
+mm_modem_icera_init (gpointer g_iface)
+{
+ static gboolean initialized = FALSE;
+
+ if (!initialized) {
+ initialized = TRUE;
+ }
+}
+
+GType
+mm_modem_icera_get_type (void)
+{
+ static GType icera_type = 0;
+
+ if (!G_UNLIKELY (icera_type)) {
+ const GTypeInfo icera_info = {
+ sizeof (MMModemIcera), /* class_size */
+ mm_modem_icera_init, /* base_init */
+ NULL, /* base_finalize */
+ NULL,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0, /* n_preallocs */
+ NULL
+ };
+
+ icera_type = g_type_register_static (G_TYPE_INTERFACE,
+ "MMModemIcera",
+ &icera_info, 0);
+
+ g_type_interface_add_prerequisite (icera_type, MM_TYPE_MODEM);
+ }
+
+ return icera_type;
+}
+
diff --git a/plugins/mm-modem-icera.h b/plugins/mm-modem-icera.h
new file mode 100644
index 0000000..71258d2
--- /dev/null
+++ b/plugins/mm-modem-icera.h
@@ -0,0 +1,89 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ */
+
+/******************************************
+ * Generic utilities for Icera-based modems
+ ******************************************/
+
+#ifndef MM_MODEM_ICERA_H
+#define MM_MODEM_ICERA_H
+
+#include <glib-object.h>
+
+#include "mm-modem-gsm.h"
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_ICERA (mm_modem_icera_get_type ())
+#define MM_MODEM_ICERA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_ICERA, MMModemIcera))
+#define MM_IS_MODEM_ICERA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_ICERA))
+#define MM_MODEM_ICERA_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_MODEM_ICERA, MMModemIcera))
+
+typedef struct _MMModemIceraPrivate MMModemIceraPrivate;
+
+typedef struct _MMModemIcera MMModemIcera;
+
+struct _MMModemIcera {
+ GTypeInterface g_iface;
+
+ MMModemIceraPrivate *priv;
+};
+
+GType mm_modem_icera_get_type (void);
+
+void mm_modem_icera_prepare (MMModemIcera *self);
+
+void mm_modem_icera_cleanup (MMModemIcera *self);
+
+void mm_modem_icera_get_allowed_mode (MMModemIcera *self,
+ MMModemUIntFn callback,
+ gpointer user_data);
+
+void mm_modem_icera_set_allowed_mode (MMModemIcera *self,
+ MMModemGsmAllowedMode mode,
+ MMModemFn callback,
+ gpointer user_data);
+
+void mm_modem_icera_register_unsolicted_handlers (MMModemIcera *self,
+ MMAtSerialPort *port);
+
+void mm_modem_icera_change_unsolicited_messages (MMModemIcera *self,
+ gboolean enabled);
+
+void mm_modem_icera_get_access_technology (MMModemIcera *self,
+ MMModemUIntFn callback,
+ gpointer user_data);
+
+void mm_modem_icera_is_icera (MMModemIcera *self,
+ MMModemUIntFn callback,
+ gpointer user_data);
+
+void mm_modem_icera_do_disconnect (MMGenericGsm *gsm,
+ gint cid,
+ MMModemFn callback,
+ gpointer user_data);
+
+void mm_modem_icera_simple_connect (MMModemIcera *self, GHashTable *properties);
+
+void mm_modem_icera_do_connect (MMModemIcera *self,
+ const char *number,
+ MMModemFn callback,
+ gpointer user_data);
+
+void mm_modem_icera_get_ip4_config (MMModemIcera *self,
+ MMModemIp4Fn callback,
+ gpointer user_data);
+
+#endif /* MM_MODEM_ICERA_H */
+
diff --git a/plugins/mm-modem-linktop.c b/plugins/mm-modem-linktop.c
new file mode 100644
index 0000000..923c219
--- /dev/null
+++ b/plugins/mm-modem-linktop.c
@@ -0,0 +1,208 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "mm-modem-linktop.h"
+#include "mm-serial-parsers.h"
+#include "mm-errors.h"
+
+#define LINKTOP_NETWORK_MODE_ANY 1
+#define LINKTOP_NETWORK_MODE_2G 5
+#define LINKTOP_NETWORK_MODE_3G 6
+
+static void modem_init (MMModem *modem_class);
+
+G_DEFINE_TYPE_EXTENDED (MMModemLinktop, mm_modem_linktop, MM_TYPE_GENERIC_GSM, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init))
+
+
+MMModem *
+mm_modem_linktop_new (const char *device,
+ const char *driver,
+ const char *plugin,
+ guint32 vendor,
+ guint32 product)
+{
+ g_return_val_if_fail (device != NULL, NULL);
+ g_return_val_if_fail (driver != NULL, NULL);
+ g_return_val_if_fail (plugin != NULL, NULL);
+
+ return MM_MODEM (g_object_new (MM_TYPE_MODEM_LINKTOP,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
+ NULL));
+}
+
+static gboolean
+grab_port (MMModem *modem,
+ const char *subsys,
+ const char *name,
+ MMPortType suggested_type,
+ gpointer user_data,
+ GError **error)
+{
+ MMGenericGsm *gsm = MM_GENERIC_GSM (modem);
+ MMPortType ptype = MM_PORT_TYPE_IGNORED;
+ MMPort *port = NULL;
+
+ if (suggested_type == MM_PORT_TYPE_UNKNOWN) {
+ if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY))
+ ptype = MM_PORT_TYPE_PRIMARY;
+ else if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_SECONDARY))
+ ptype = MM_PORT_TYPE_SECONDARY;
+ } else
+ ptype = suggested_type;
+
+ port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
+ if (port && MM_IS_AT_SERIAL_PORT (port)) {
+ mm_at_serial_port_set_response_parser (MM_AT_SERIAL_PORT (port),
+ mm_serial_parser_v1_e1_parse,
+ mm_serial_parser_v1_e1_new (),
+ mm_serial_parser_v1_e1_destroy);
+ }
+
+ return !!port;
+}
+
+static int
+linktop_parse_allowed_mode (MMModemGsmAllowedMode network_mode)
+{
+ switch (network_mode) {
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY:
+ return LINKTOP_NETWORK_MODE_2G;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY:
+ return LINKTOP_NETWORK_MODE_3G;
+ default:
+ return LINKTOP_NETWORK_MODE_ANY;
+ }
+}
+
+static void
+linktop_set_allowed_mode_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ if (error)
+ info->error = g_error_copy (error);
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+set_allowed_mode (MMGenericGsm *gsm,
+ MMModemGsmAllowedMode mode,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ char *command;
+ MMAtSerialPort *port;
+
+ info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (gsm, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ command = g_strdup_printf ("+CFUN=%d", linktop_parse_allowed_mode (mode));
+ mm_at_serial_port_queue_command (port, command, 3, linktop_set_allowed_mode_done, info);
+ g_free (command);
+}
+
+static void
+get_allowed_mode_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ gboolean parsed = FALSE;
+
+ if (error)
+ info->error = g_error_copy (error);
+ else if (!g_str_has_prefix (response->str, "CFUN: ")) {
+ MMModemGsmAllowedMode mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+ int a;
+
+ a = atoi (response->str + 6);
+ if (a == LINKTOP_NETWORK_MODE_2G)
+ mode = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY;
+ else if (a == LINKTOP_NETWORK_MODE_3G)
+ mode = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY;
+
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mode), NULL);
+ parsed = TRUE;
+ }
+
+ if (!error && !parsed)
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Could not parse allowed mode results");
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_allowed_mode (MMGenericGsm *gsm,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
+
+ info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (gsm, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (port, "+CFUN?", 3, get_allowed_mode_done, info);
+}
+
+/*****************************************************************************/
+
+static void
+modem_init (MMModem *modem_class)
+{
+ modem_class->grab_port = grab_port;
+}
+
+static void
+mm_modem_linktop_init (MMModemLinktop *self)
+{
+}
+
+static void
+mm_modem_linktop_class_init (MMModemLinktopClass *klass)
+{
+ MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
+
+ gsm_class->get_allowed_mode = get_allowed_mode;
+ gsm_class->set_allowed_mode = set_allowed_mode;
+}
+
diff --git a/plugins/mm-modem-linktop.h b/plugins/mm-modem-linktop.h
new file mode 100644
index 0000000..4b7153e
--- /dev/null
+++ b/plugins/mm-modem-linktop.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_MODEM_LINKTOP_H
+#define MM_MODEM_LINKTOP_H
+
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_LINKTOP (mm_modem_linktop_get_type ())
+#define MM_MODEM_LINKTOP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_LINKTOP, MMModemLinktop))
+#define MM_MODEM_LINKTOP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_LINKTOP, MMModemLinktopClass))
+#define MM_IS_MODEM_LINKTOP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_LINKTOP))
+#define MM_IS_MODEM_LINKTOP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_LINKTOP))
+#define MM_MODEM_LINKTOP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_LINKTOP, MMModemLinktopClass))
+
+typedef struct {
+ MMGenericGsm parent;
+} MMModemLinktop;
+
+typedef struct {
+ MMGenericGsmClass parent;
+} MMModemLinktopClass;
+
+GType mm_modem_linktop_get_type (void);
+
+MMModem *mm_modem_linktop_new (const char *data,
+ const char *driver,
+ const char *plugin,
+ guint32 vendor,
+ guint32 product);
+
+#endif /* MM_MODEM_LINKTOP_H */
diff --git a/plugins/mm-modem-longcheer-gsm.c b/plugins/mm-modem-longcheer-gsm.c
index 62980f7..33763e2 100644
--- a/plugins/mm-modem-longcheer-gsm.c
+++ b/plugins/mm-modem-longcheer-gsm.c
@@ -30,7 +30,9 @@ G_DEFINE_TYPE (MMModemLongcheerGsm, mm_modem_longcheer_gsm, MM_TYPE_GENERIC_GSM)
MMModem *
mm_modem_longcheer_gsm_new (const char *device,
const char *driver,
- const char *plugin)
+ const char *plugin,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -40,6 +42,8 @@ mm_modem_longcheer_gsm_new (const char *device,
MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
diff --git a/plugins/mm-modem-longcheer-gsm.h b/plugins/mm-modem-longcheer-gsm.h
index 5383c52..e9abfbe 100644
--- a/plugins/mm-modem-longcheer-gsm.h
+++ b/plugins/mm-modem-longcheer-gsm.h
@@ -38,6 +38,8 @@ GType mm_modem_longcheer_gsm_get_type (void);
MMModem *mm_modem_longcheer_gsm_new (const char *device,
const char *driver,
- const char *plugin);
+ const char *plugin,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_LONGCHEER_H */
diff --git a/plugins/mm-modem-mbm.c b/plugins/mm-modem-mbm.c
index 7f6bc9c..9303453 100644
--- a/plugins/mm-modem-mbm.c
+++ b/plugins/mm-modem-mbm.c
@@ -1,7 +1,7 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2008 - 2010 Ericsson AB
- * Copyright (C) 2009 - 2010 Red Hat, Inc.
+ * Copyright (C) 2009 - 2011 Red Hat, Inc.
*
* Author: Per Hallsmark <per.hallsmark@ericsson.com>
* Bjorn Runaker <bjorn.runaker@ericsson.com>
@@ -31,6 +31,7 @@
#include "mm-modem-gsm-card.h"
#include "mm-errors.h"
#include "mm-callback-info.h"
+#include "mm-log.h"
static void modem_init (MMModem *modem_class);
static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class);
@@ -49,8 +50,6 @@ G_DEFINE_TYPE_EXTENDED (MMModemMbm, mm_modem_mbm, MM_TYPE_GENERIC_GSM, 0,
#define MBM_E2NAP_CONNECTED 1
#define MBM_E2NAP_CONNECTING 2
-#define MBM_SIGNAL_INDICATOR 2
-
#define MBM_NETWORK_MODE_ANY 1
#define MBM_NETWORK_MODE_2G 5
#define MBM_NETWORK_MODE_3G 6
@@ -82,7 +81,9 @@ mbm_modem_authenticate (MMModemMbm *self,
MMModem *
mm_modem_mbm_new (const char *device,
const char *driver,
- const char *plugin)
+ const char *plugin,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -93,6 +94,8 @@ mm_modem_mbm_new (const char *device,
MM_MODEM_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
MM_MODEM_IP_METHOD, MM_MODEM_IP_METHOD_DHCP,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
@@ -349,7 +352,6 @@ mbm_enable_done (MMAtSerialPort *port,
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
/* Start unsolicited signal strength and access technology responses */
- mm_at_serial_port_queue_command (port, "+CMER=3,0,0,1", 3, NULL, NULL);
mm_at_serial_port_queue_command (port, "*ERINFO=1", 3, NULL, NULL);
mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
@@ -409,7 +411,7 @@ mbm_emrdy_done (MMAtSerialPort *port,
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (info->modem);
if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT))
- g_warning ("%s: timed out waiting for EMRDY response.", __func__);
+ mm_warn ("timed out waiting for EMRDY response.");
else
priv->have_emrdy = TRUE;
@@ -473,7 +475,7 @@ disable (MMModem *modem,
g_assert (primary);
/* Turn off unsolicited responses */
- mm_at_serial_port_queue_command (primary, "+CMER=0;*ERINFO=0", 5, disable_unsolicited_done, info);
+ mm_at_serial_port_queue_command (primary, "*ERINFO=0", 5, disable_unsolicited_done, info);
}
static void
@@ -509,6 +511,24 @@ do_disconnect (MMGenericGsm *gsm,
}
static void
+reset (MMModem *modem,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
+
+ info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
+
+ /* Ensure we have a usable port to use for the command */
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error);
+ if (port)
+ mm_at_serial_port_queue_command (port, "*E2RESET", 3, NULL, NULL);
+
+ mm_callback_info_schedule (info);
+}
+
+static void
factory_reset_done (MMAtSerialPort *port,
GString *response,
GError *error,
@@ -580,29 +600,6 @@ mbm_pacsp_received (MMAtSerialPort *port,
}
static void
-mbm_ciev_received (MMAtSerialPort *port,
- GMatchInfo *info,
- gpointer user_data)
-{
- int quality = 0, ind = 0;
- char *str;
-
- str = g_match_info_fetch (info, 1);
- if (str)
- ind = atoi (str);
- g_free (str);
-
- if (ind == MBM_SIGNAL_INDICATOR) {
- str = g_match_info_fetch (info, 2);
- if (str) {
- quality = atoi (str);
- mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (user_data), quality * 20);
- }
- g_free (str);
- }
-}
-
-static void
mbm_do_connect_done (MMModemMbm *self, gboolean success)
{
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
@@ -636,16 +633,16 @@ mbm_e2nap_received (MMAtSerialPort *port,
g_free (str);
if (MBM_E2NAP_DISCONNECTED == state) {
- g_debug ("%s: disconnected", __func__);
+ mm_dbg ("disconnected");
mbm_do_connect_done (MM_MODEM_MBM (user_data), FALSE);
} else if (MBM_E2NAP_CONNECTED == state) {
- g_debug ("%s: connected", __func__);
+ mm_dbg ("connected");
mbm_do_connect_done (MM_MODEM_MBM (user_data), TRUE);
} else if (MBM_E2NAP_CONNECTING == state)
- g_debug("%s: connecting", __func__);
+ mm_dbg ("connecting");
else {
/* Should not happen */
- g_debug("%s: unhandled E2NAP state %d", __func__, state);
+ mm_dbg ("unhandled E2NAP state %d", state);
mbm_do_connect_done (MM_MODEM_MBM (user_data), FALSE);
}
}
@@ -724,18 +721,15 @@ mbm_auth_done (MMSerialPort *port,
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMGenericGsm *modem = MM_GENERIC_GSM (info->modem);
char *command;
- guint32 cid;
if (error) {
mm_generic_gsm_connect_complete (modem, error, info);
return;
}
- cid = mm_generic_gsm_get_cid (modem);
-
mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "AT*E2NAP=1", 3, NULL, NULL);
- command = g_strdup_printf ("AT*ENAP=1,%d", cid);
+ command = g_strdup_printf ("AT*ENAP=1,%d", mm_generic_gsm_get_cid (modem));
mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), command, 3, enap_done, user_data);
g_free (command);
}
@@ -818,7 +812,7 @@ send_epin_done (MMAtSerialPort *port,
else if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PUK2))
sscanf (response->str, "*EPIN: %*d, %*d, %*d, %d", &attempts_left);
else {
- g_debug ("%s: unhandled pin type '%s'", __func__, pin_type);
+ mm_dbg ("unhandled pin type '%s'", pin_type);
info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Unhandled PIN type");
}
@@ -845,7 +839,7 @@ mbm_get_unlock_retries (MMModemGsmCard *modem,
char *command;
MMCallbackInfo *info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- g_debug ("%s: pin type '%s'", __func__, pin_type);
+ mm_dbg ("pin type '%s'", pin_type);
/* Ensure we have a usable port to use for the command */
port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error);
@@ -922,10 +916,6 @@ grab_port (MMModem *modem,
mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, mbm_pacsp_received, modem, NULL);
g_regex_unref (regex);
- regex = g_regex_new ("\\r\\n\\+CIEV: (\\d),(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, mbm_ciev_received, modem, NULL);
- g_regex_unref (regex);
-
/* also consume unsolicited mbm messages we are not interested in them - see LP: #416418 */
regex = g_regex_new ("\\R\\*ESTKSMENU:.*\\R", G_REGEX_RAW | G_REGEX_OPTIMIZE | G_REGEX_MULTILINE | G_REGEX_NEWLINE_CRLF, G_REGEX_MATCH_NEWLINE_CRLF, NULL);
mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
@@ -969,6 +959,7 @@ modem_init (MMModem *modem_class)
modem_class->grab_port = grab_port;
modem_class->disable = disable;
modem_class->connect = do_connect;
+ modem_class->reset = reset;
modem_class->factory_reset = factory_reset;
}
diff --git a/plugins/mm-modem-mbm.h b/plugins/mm-modem-mbm.h
index db0f627..bb1c2ff 100644
--- a/plugins/mm-modem-mbm.h
+++ b/plugins/mm-modem-mbm.h
@@ -43,6 +43,8 @@ GType mm_modem_mbm_get_type (void);
MMModem *mm_modem_mbm_new (const char *device,
const char *driver,
- const char *plugin_name);
+ const char *plugin_name,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_MBM_H */
diff --git a/plugins/mm-modem-moto-c-gsm.c b/plugins/mm-modem-moto-c-gsm.c
index 5910ff2..cd7b4ed 100644
--- a/plugins/mm-modem-moto-c-gsm.c
+++ b/plugins/mm-modem-moto-c-gsm.c
@@ -35,7 +35,9 @@ G_DEFINE_TYPE_EXTENDED (MMModemMotoCGsm, mm_modem_moto_c_gsm, MM_TYPE_GENERIC_GS
MMModem *
mm_modem_moto_c_gsm_new (const char *device,
const char *driver,
- const char *plugin)
+ const char *plugin,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -45,6 +47,8 @@ mm_modem_moto_c_gsm_new (const char *device,
MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
diff --git a/plugins/mm-modem-moto-c-gsm.h b/plugins/mm-modem-moto-c-gsm.h
index eb1dad1..a8ddd6d 100644
--- a/plugins/mm-modem-moto-c-gsm.h
+++ b/plugins/mm-modem-moto-c-gsm.h
@@ -38,6 +38,8 @@ GType mm_modem_moto_c_gsm_get_type (void);
MMModem *mm_modem_moto_c_gsm_new (const char *device,
const char *driver,
- const char *plugin_name);
+ const char *plugin_name,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_MOTO_C_GSM_H */
diff --git a/plugins/mm-modem-nokia.c b/plugins/mm-modem-nokia.c
index eb90287..56b8c91 100644
--- a/plugins/mm-modem-nokia.c
+++ b/plugins/mm-modem-nokia.c
@@ -30,7 +30,9 @@ G_DEFINE_TYPE_EXTENDED (MMModemNokia, mm_modem_nokia, MM_TYPE_GENERIC_GSM, 0,
MMModem *
mm_modem_nokia_new (const char *device,
const char *driver,
- const char *plugin)
+ const char *plugin,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -40,6 +42,8 @@ mm_modem_nokia_new (const char *device,
MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
@@ -54,6 +58,7 @@ grab_port (MMModem *modem,
MMGenericGsm *gsm = MM_GENERIC_GSM (modem);
MMPortType ptype = MM_PORT_TYPE_IGNORED;
MMPort *port = NULL;
+ gulong send_delay = 5000;
if (suggested_type == MM_PORT_TYPE_UNKNOWN) {
if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY))
@@ -71,6 +76,9 @@ grab_port (MMModem *modem,
mm_serial_parser_v1_e1_destroy);
}
+ /* N900 appears to need longer delay between port bytes */
+ g_object_set (G_OBJECT (port), MM_SERIAL_PORT_SEND_DELAY, send_delay, NULL);
+
return !!port;
}
diff --git a/plugins/mm-modem-nokia.h b/plugins/mm-modem-nokia.h
index 0e24619..0873d2d 100644
--- a/plugins/mm-modem-nokia.h
+++ b/plugins/mm-modem-nokia.h
@@ -38,6 +38,8 @@ GType mm_modem_nokia_get_type (void);
MMModem *mm_modem_nokia_new (const char *data,
const char *driver,
- const char *plugin);
+ const char *plugin,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_NOKIA_H */
diff --git a/plugins/mm-modem-novatel-cdma.c b/plugins/mm-modem-novatel-cdma.c
index 64ee15f..6b8c4aa 100644
--- a/plugins/mm-modem-novatel-cdma.c
+++ b/plugins/mm-modem-novatel-cdma.c
@@ -21,6 +21,8 @@
#include <ctype.h>
#include "mm-modem-novatel-cdma.h"
+#include "mm-modem-helpers.h"
+#include "libqcdm/src/commands.h"
#include "mm-errors.h"
#include "mm-callback-info.h"
@@ -35,7 +37,9 @@ mm_modem_novatel_cdma_new (const char *device,
const char *driver,
const char *plugin,
gboolean evdo_rev0,
- gboolean evdo_revA)
+ gboolean evdo_revA,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -72,6 +76,8 @@ get_one_qual (const char *reply, const char *tag)
{
int qual = -1;
const char *p;
+ long int dbm;
+ gboolean success = FALSE;
p = strstr (reply, tag);
if (!p)
@@ -83,17 +89,26 @@ get_one_qual (const char *reply, const char *tag)
/* Skip spaces */
while (isspace (*p))
p++;
- if (*p == '-') {
- long int dbm;
-
- errno = 0;
- dbm = strtol (p, NULL, 10);
- if (dbm < 0 && errno == 0) {
- dbm = CLAMP (dbm, -113, -51);
- qual = 100 - ((dbm + 51) * 100 / (-113 + 51));
+
+ errno = 0;
+ dbm = strtol (p, NULL, 10);
+ if (errno == 0) {
+ if (*p == '-') {
+ /* Some cards appear to use RX0/RX1 and output RSSI in negative dBm */
+ if (dbm < 0)
+ success = TRUE;
+ } else if (isdigit (*p) && (dbm > 0) && (dbm < 115)) {
+ /* S720 appears to use "1x RSSI" and print RSSI in dBm without '-' */
+ dbm *= -1;
+ success = TRUE;
}
}
+ if (success) {
+ dbm = CLAMP (dbm, -113, -51);
+ qual = 100 - ((dbm + 51) * 100 / (-113 + 51));
+ }
+
return qual;
}
@@ -123,6 +138,8 @@ get_rssi_done (MMAtSerialPort *port,
/* Parse the signal quality */
qual = get_one_qual (response->str, "RX0=");
if (qual < 0)
+ qual = get_one_qual (response->str, "1x RSSI=");
+ if (qual < 0)
qual = get_one_qual (response->str, "RX1=");
if (qual >= 0) {
@@ -165,6 +182,115 @@ get_signal_quality (MMModemCdma *modem,
/*****************************************************************************/
static void
+parse_modem_snapshot (MMCallbackInfo *info, QCDMResult *result)
+{
+ MMModemCdmaRegistrationState evdo_state, cdma1x_state, new_state;
+ guint8 eri = 0;
+
+ g_return_if_fail (info != NULL);
+ g_return_if_fail (result != NULL);
+
+ evdo_state = mm_generic_cdma_query_reg_state_get_callback_evdo_state (info);
+ cdma1x_state = mm_generic_cdma_query_reg_state_get_callback_1x_state (info);
+
+ /* Roaming? */
+ if (qcdm_result_get_uint8 (result, QCDM_CMD_NW_SUBSYS_MODEM_SNAPSHOT_CDMA_ITEM_ERI, &eri)) {
+ char *str;
+ gboolean roaming = FALSE;
+
+ str = g_strdup_printf ("%u", eri);
+ if (mm_cdma_parse_eri (str, &roaming, NULL, NULL)) {
+ new_state = roaming ? MM_MODEM_CDMA_REGISTRATION_STATE_HOME : MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING;
+ if (cdma1x_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)
+ mm_generic_cdma_query_reg_state_set_callback_1x_state (info, new_state);
+ if (evdo_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)
+ mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, new_state);
+ }
+ g_free (str);
+ }
+}
+
+static void
+reg_nwsnap_6500_cb (MMQcdmSerialPort *port,
+ GByteArray *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ QCDMResult *result;
+
+ if (!error) {
+ result = qcdm_cmd_nw_subsys_modem_snapshot_cdma_result ((const char *) response->data, response->len, NULL);
+ if (result) {
+ parse_modem_snapshot (info, result);
+ qcdm_result_unref (result);
+ }
+ }
+ mm_callback_info_schedule (info);
+}
+
+static void
+reg_nwsnap_6800_cb (MMQcdmSerialPort *port,
+ GByteArray *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ QCDMResult *result;
+ GByteArray *nwsnap;
+
+ if (error)
+ goto done;
+
+ /* Parse the response */
+ result = qcdm_cmd_nw_subsys_modem_snapshot_cdma_result ((const char *) response->data, response->len, &info->error);
+ if (!result) {
+ g_clear_error (&info->error);
+
+ /* Try for MSM6500 */
+ nwsnap = g_byte_array_sized_new (25);
+ nwsnap->len = qcdm_cmd_nw_subsys_modem_snapshot_cdma_new ((char *) nwsnap->data, 25, QCDM_NW_CHIPSET_6500, NULL);
+ g_assert (nwsnap->len);
+ mm_qcdm_serial_port_queue_command (port, nwsnap, 3, reg_nwsnap_6500_cb, info);
+ return;
+ }
+
+ parse_modem_snapshot (info, result);
+ qcdm_result_unref (result);
+
+done:
+ mm_callback_info_schedule (info);
+}
+
+static void
+query_registration_state (MMGenericCdma *cdma,
+ MMModemCdmaRegistrationState cur_cdma_state,
+ MMModemCdmaRegistrationState cur_evdo_state,
+ MMModemCdmaRegistrationStateFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMQcdmSerialPort *port;
+ GByteArray *nwsnap;
+
+ info = mm_generic_cdma_query_reg_state_callback_info_new (cdma, cur_cdma_state, cur_evdo_state, callback, user_data);
+
+ port = mm_generic_cdma_get_best_qcdm_port (cdma, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ /* Try MSM6800 first since newer cards use that */
+ nwsnap = g_byte_array_sized_new (25);
+ nwsnap->len = qcdm_cmd_nw_subsys_modem_snapshot_cdma_new ((char *) nwsnap->data, 25, QCDM_NW_CHIPSET_6800, NULL);
+ g_assert (nwsnap->len);
+ mm_qcdm_serial_port_queue_command (port, nwsnap, 3, reg_nwsnap_6800_cb, info);
+}
+
+/*****************************************************************************/
+
+static void
modem_cdma_init (MMModemCdma *cdma_class)
{
cdma_class->get_signal_quality = get_signal_quality;
@@ -178,6 +304,10 @@ mm_modem_novatel_cdma_init (MMModemNovatelCdma *self)
static void
mm_modem_novatel_cdma_class_init (MMModemNovatelCdmaClass *klass)
{
+ MMGenericCdmaClass *generic_class = MM_GENERIC_CDMA_CLASS (klass);
+
mm_modem_novatel_cdma_parent_class = g_type_class_peek_parent (klass);
+
+ generic_class->query_registration_state = query_registration_state;
}
diff --git a/plugins/mm-modem-novatel-cdma.h b/plugins/mm-modem-novatel-cdma.h
index 4d38d8e..c2319ef 100644
--- a/plugins/mm-modem-novatel-cdma.h
+++ b/plugins/mm-modem-novatel-cdma.h
@@ -40,6 +40,8 @@ MMModem *mm_modem_novatel_cdma_new (const char *device,
const char *driver,
const char *plugin,
gboolean evdo_rev0,
- gboolean evdo_revA);
+ gboolean evdo_revA,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_NOVATEL_CDMA_H */
diff --git a/plugins/mm-modem-novatel-gsm.c b/plugins/mm-modem-novatel-gsm.c
index 584156f..64a81bd 100644
--- a/plugins/mm-modem-novatel-gsm.c
+++ b/plugins/mm-modem-novatel-gsm.c
@@ -33,7 +33,9 @@ G_DEFINE_TYPE_EXTENDED (MMModemNovatelGsm, mm_modem_novatel_gsm, MM_TYPE_GENERIC
MMModem *
mm_modem_novatel_gsm_new (const char *device,
const char *driver,
- const char *plugin)
+ const char *plugin,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -43,6 +45,8 @@ mm_modem_novatel_gsm_new (const char *device,
MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
diff --git a/plugins/mm-modem-novatel-gsm.h b/plugins/mm-modem-novatel-gsm.h
index c2e1138..12b0060 100644
--- a/plugins/mm-modem-novatel-gsm.h
+++ b/plugins/mm-modem-novatel-gsm.h
@@ -38,6 +38,8 @@ GType mm_modem_novatel_gsm_get_type (void);
MMModem *mm_modem_novatel_gsm_new (const char *device,
const char *driver,
- const char *plugin_name);
+ const char *plugin_name,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_NOVATEL_GSM_H */
diff --git a/plugins/mm-modem-option.c b/plugins/mm-modem-option.c
index ac04b0b..b15e704 100644
--- a/plugins/mm-modem-option.c
+++ b/plugins/mm-modem-option.c
@@ -36,7 +36,9 @@ typedef struct {
MMModem *
mm_modem_option_new (const char *device,
const char *driver,
- const char *plugin)
+ const char *plugin,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -46,6 +48,8 @@ mm_modem_option_new (const char *device,
MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
diff --git a/plugins/mm-modem-option.h b/plugins/mm-modem-option.h
index 4e88607..3af9b1e 100644
--- a/plugins/mm-modem-option.h
+++ b/plugins/mm-modem-option.h
@@ -38,6 +38,8 @@ GType mm_modem_option_get_type (void);
MMModem *mm_modem_option_new (const char *device,
const char *driver,
- const char *plugin_name);
+ const char *plugin_name,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_OPTION_H */
diff --git a/plugins/mm-modem-sierra-cdma.c b/plugins/mm-modem-sierra-cdma.c
index fc62bf6..1168c83 100644
--- a/plugins/mm-modem-sierra-cdma.c
+++ b/plugins/mm-modem-sierra-cdma.c
@@ -51,7 +51,9 @@ mm_modem_sierra_cdma_new (const char *device,
const char *driver,
const char *plugin,
gboolean evdo_rev0,
- gboolean evdo_revA)
+ gboolean evdo_revA,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -63,6 +65,8 @@ mm_modem_sierra_cdma_new (const char *device,
MM_MODEM_PLUGIN, plugin,
MM_GENERIC_CDMA_EVDO_REV0, evdo_rev0,
MM_GENERIC_CDMA_EVDO_REVA, evdo_revA,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
diff --git a/plugins/mm-modem-sierra-cdma.h b/plugins/mm-modem-sierra-cdma.h
index 9111b73..a33b1bc 100644
--- a/plugins/mm-modem-sierra-cdma.h
+++ b/plugins/mm-modem-sierra-cdma.h
@@ -40,6 +40,8 @@ MMModem *mm_modem_sierra_cdma_new (const char *device,
const char *driver,
const char *plugin,
gboolean evdo_rev0,
- gboolean evdo_revA);
+ gboolean evdo_revA,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_SIERRA_CDMA_H */
diff --git a/plugins/mm-modem-sierra-gsm.c b/plugins/mm-modem-sierra-gsm.c
index bf5df31..d4636d7 100644
--- a/plugins/mm-modem-sierra-gsm.c
+++ b/plugins/mm-modem-sierra-gsm.c
@@ -15,30 +15,39 @@
*/
#include <config.h>
+#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "mm-modem-sierra-gsm.h"
#include "mm-errors.h"
+#include "mm-modem-simple.h"
#include "mm-callback-info.h"
#include "mm-modem-helpers.h"
static void modem_init (MMModem *modem_class);
+static void modem_simple_init (MMModemSimple *class);
G_DEFINE_TYPE_EXTENDED (MMModemSierraGsm, mm_modem_sierra_gsm, MM_TYPE_GENERIC_GSM, 0,
- G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init))
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simple_init))
#define MM_MODEM_SIERRA_GSM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_SIERRA_GSM, MMModemSierraGsmPrivate))
typedef struct {
guint enable_wait_id;
+ gboolean has_net;
+ char *username;
+ char *password;
} MMModemSierraGsmPrivate;
MMModem *
mm_modem_sierra_gsm_new (const char *device,
const char *driver,
- const char *plugin)
+ const char *plugin,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -48,6 +57,8 @@ mm_modem_sierra_gsm_new (const char *device,
MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
@@ -238,6 +249,85 @@ get_access_technology (MMGenericGsm *modem,
mm_at_serial_port_queue_command (port, "*CNTI=0", 3, get_act_request_done, info);
}
+static void
+get_sim_iccid_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ const char *p;
+ char buf[21];
+ int i;
+
+ if (error) {
+ info->error = g_error_copy (error);
+ goto done;
+ }
+
+ p = mm_strip_tag (response->str, "!ICCID:");
+ if (!p) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Failed to parse !ICCID response");
+ goto done;
+ }
+
+ memset (buf, 0, sizeof (buf));
+ for (i = 0; i < 20; i++) {
+ if (!isdigit (p[i]) && (p[i] != 'F') && (p[i] == 'f')) {
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "CRSM ICCID response contained invalid character '%c'",
+ p[i]);
+ goto done;
+ }
+ if (p[i] == 'F' || p[i] == 'f') {
+ buf[i] = 0;
+ break;
+ }
+ buf[i] = p[i];
+ }
+
+ if (i == 19 || i == 20)
+ mm_callback_info_set_result (info, g_strdup (buf), g_free);
+ else {
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Invalid +CRSM ICCID response size (was %d, expected 19 or 20)",
+ i);
+ }
+
+done:
+ mm_serial_port_close (MM_SERIAL_PORT (port));
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_sim_iccid (MMGenericGsm *modem,
+ MMModemStringFn callback,
+ gpointer callback_data)
+{
+ MMAtSerialPort *port;
+ MMCallbackInfo *info;
+ GError *error = NULL;
+
+ port = mm_generic_gsm_get_best_at_port (modem, &error);
+ if (!port)
+ goto error;
+
+ if (!mm_serial_port_open (MM_SERIAL_PORT (port), &error))
+ goto error;
+
+ info = mm_callback_info_string_new (MM_MODEM (modem), callback, callback_data);
+ mm_at_serial_port_queue_command (port, "!ICCID?", 3, get_sim_iccid_done, info);
+ return;
+
+error:
+ callback (MM_MODEM (modem), NULL, error, callback_data);
+ g_clear_error (&error);
+}
+
/*****************************************************************************/
/* Modem class override functions */
/*****************************************************************************/
@@ -302,25 +392,233 @@ grab_port (MMModem *modem,
port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
- if (port && MM_IS_AT_SERIAL_PORT (port)) {
- GRegex *regex;
+ if (port) {
+ if (MM_IS_AT_SERIAL_PORT (port)) {
+ GRegex *regex;
- g_object_set (G_OBJECT (port), MM_PORT_CARRIER_DETECT, FALSE, NULL);
+ g_object_set (G_OBJECT (port), MM_PORT_CARRIER_DETECT, FALSE, NULL);
- regex = g_regex_new ("\\r\\n\\+PACSP0\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
- g_regex_unref (regex);
+ regex = g_regex_new ("\\r\\n\\+PACSP0\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ g_regex_unref (regex);
+ } else if (mm_port_get_subsys (port) == MM_PORT_SUBSYS_NET) {
+ MM_MODEM_SIERRA_GSM_GET_PRIVATE (gsm)->has_net = TRUE;
+ g_object_set (G_OBJECT (gsm), MM_MODEM_IP_METHOD, MM_MODEM_IP_METHOD_DHCP, NULL);
+ }
}
return !!port;
}
+static void
+ppp_connect_done (MMModem *modem, GError *error, gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+
+ info->error = mm_modem_check_removed (modem, error);
+ mm_callback_info_schedule (info);
+}
+
+static void
+net_activate_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), error, info);
+}
+
+
+static void
+auth_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ gint cid;
+ char *command;
+
+ if (error) {
+ info->error = g_error_copy (error);
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (info->modem));
+ g_warn_if_fail (cid >= 0);
+
+ /* Activate data on the net port */
+ command = g_strdup_printf ("!SCACT=1,%d", cid);
+ mm_at_serial_port_queue_command (port, command, 3, net_activate_done, info);
+ g_free (command);
+}
+
+static void
+ps_attach_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ MMModemSierraGsmPrivate *priv;
+ MMModem *parent_modem_iface;
+ const char *number;
+
+ if (error) {
+ info->error = g_error_copy (error);
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (info->modem);
+ if (priv->has_net) {
+ gint cid;
+ char *command;
+
+ /* If we have a net interface, we don't do PPP */
+
+ cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (info->modem));
+ g_warn_if_fail (cid >= 0);
+
+ if (!priv->username || !priv->password)
+ command = g_strdup_printf ("$QCPDPP=%d,0", cid);
+ else {
+ command = g_strdup_printf ("$QCPDPP=%d,1,\"%s\",\"%s\"",
+ cid,
+ priv->password ? priv->password : "",
+ priv->username ? priv->username : "");
+
+ }
+
+ mm_at_serial_port_queue_command (port, command, 3, auth_done, info);
+ g_free (command);
+ } else {
+ /* We've got a PS attach, chain up to parent for the connect */
+ number = mm_callback_info_get_data (info, "number");
+ parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (info->modem));
+ parent_modem_iface->connect (info->modem, number, ppp_connect_done, info);
+ }
+}
+
+static void
+do_connect (MMModem *modem,
+ const char *number,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
+
+ mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE);
+
+ info = mm_callback_info_new (modem, callback, user_data);
+ mm_callback_info_set_data (info, "number", g_strdup (number), g_free);
+
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ /* Try to initiate a PS attach. Some Sierra modems can get into a
+ * state where if there is no PS attach when dialing, the next time
+ * the modem tries to connect it won't ever register with the network.
+ */
+ mm_at_serial_port_queue_command (port, "+CGATT=1", 10, ps_attach_done, info);
+}
+
+static void
+clear_user_pass (MMModemSierraGsm *self)
+{
+ MMModemSierraGsmPrivate *priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (self);
+
+ g_free (priv->username);
+ priv->username = NULL;
+ g_free (priv->password);
+ priv->username = NULL;
+}
+
+static void
+do_disconnect (MMGenericGsm *gsm,
+ gint cid,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ clear_user_pass (MM_MODEM_SIERRA_GSM (gsm));
+
+ if (MM_MODEM_SIERRA_GSM_GET_PRIVATE (gsm)->has_net) {
+ MMAtSerialPort *primary;
+ char *command;
+
+ primary = mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
+ /* If we have a net interface, deactivate it */
+ command = g_strdup_printf ("!SCACT=0,%d", cid);
+ mm_at_serial_port_queue_command (primary, command, 3, NULL, NULL);
+ g_free (command);
+ }
+
+ MM_GENERIC_GSM_CLASS (mm_modem_sierra_gsm_parent_class)->do_disconnect (gsm, cid, callback, user_data);
+}
+
+/*****************************************************************************/
+/* Simple Modem class override functions */
+/*****************************************************************************/
+
+static char *
+simple_dup_string_property (GHashTable *properties, const char *name, GError **error)
+{
+ GValue *value;
+
+ value = (GValue *) g_hash_table_lookup (properties, name);
+ if (!value)
+ return NULL;
+
+ if (G_VALUE_HOLDS_STRING (value))
+ return g_value_dup_string (value);
+
+ g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Invalid property type for '%s': %s (string expected)",
+ name, G_VALUE_TYPE_NAME (value));
+
+ return NULL;
+}
+
+static void
+simple_connect (MMModemSimple *simple,
+ GHashTable *properties,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMModemSierraGsmPrivate *priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (simple);
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemSimple *parent_iface;
+
+ clear_user_pass (MM_MODEM_SIERRA_GSM (simple));
+ priv->username = simple_dup_string_property (properties, "username", &info->error);
+ priv->password = simple_dup_string_property (properties, "password", &info->error);
+
+ parent_iface = g_type_interface_peek_parent (MM_MODEM_SIMPLE_GET_INTERFACE (simple));
+ parent_iface->connect (MM_MODEM_SIMPLE (simple), properties, callback, info);
+}
+
/*****************************************************************************/
static void
modem_init (MMModem *modem_class)
{
modem_class->grab_port = grab_port;
+ modem_class->connect = do_connect;
+}
+
+static void
+modem_simple_init (MMModemSimple *class)
+{
+ class->connect = simple_connect;
}
static void
@@ -335,6 +633,8 @@ dispose (GObject *object)
if (priv->enable_wait_id)
g_source_remove (priv->enable_wait_id);
+
+ clear_user_pass (MM_MODEM_SIERRA_GSM (object));
}
static void
@@ -351,5 +651,7 @@ mm_modem_sierra_gsm_class_init (MMModemSierraGsmClass *klass)
gsm_class->set_allowed_mode = set_allowed_mode;
gsm_class->get_allowed_mode = get_allowed_mode;
gsm_class->get_access_technology = get_access_technology;
+ gsm_class->get_sim_iccid = get_sim_iccid;
+ gsm_class->do_disconnect = do_disconnect;
}
diff --git a/plugins/mm-modem-sierra-gsm.h b/plugins/mm-modem-sierra-gsm.h
index dd84b30..8f2391d 100644
--- a/plugins/mm-modem-sierra-gsm.h
+++ b/plugins/mm-modem-sierra-gsm.h
@@ -38,6 +38,8 @@ GType mm_modem_sierra_gsm_get_type (void);
MMModem *mm_modem_sierra_gsm_new (const char *device,
const char *driver,
- const char *plugin_name);
+ const char *plugin_name,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_SIERRA_GSM_H */
diff --git a/plugins/mm-modem-simtech-gsm.c b/plugins/mm-modem-simtech-gsm.c
index 07820b3..4a62694 100644
--- a/plugins/mm-modem-simtech-gsm.c
+++ b/plugins/mm-modem-simtech-gsm.c
@@ -34,7 +34,9 @@ G_DEFINE_TYPE_EXTENDED (MMModemSimtechGsm, mm_modem_simtech_gsm, MM_TYPE_GENERIC
MMModem *
mm_modem_simtech_gsm_new (const char *device,
const char *driver,
- const char *plugin)
+ const char *plugin,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -44,6 +46,8 @@ mm_modem_simtech_gsm_new (const char *device,
MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
diff --git a/plugins/mm-modem-simtech-gsm.h b/plugins/mm-modem-simtech-gsm.h
index 0ba3c43..85e421c 100644
--- a/plugins/mm-modem-simtech-gsm.h
+++ b/plugins/mm-modem-simtech-gsm.h
@@ -38,6 +38,8 @@ GType mm_modem_simtech_gsm_get_type (void);
MMModem *mm_modem_simtech_gsm_new (const char *device,
const char *driver,
- const char *plugin);
+ const char *plugin,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_SIMTECH_H */
diff --git a/plugins/mm-modem-x22x-gsm.c b/plugins/mm-modem-x22x-gsm.c
new file mode 100644
index 0000000..ff23297
--- /dev/null
+++ b/plugins/mm-modem-x22x-gsm.c
@@ -0,0 +1,209 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 - 2010 Red Hat, Inc.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include "mm-modem-x22x-gsm.h"
+#include "mm-at-serial-port.h"
+#include "mm-errors.h"
+#include "mm-callback-info.h"
+#include "mm-modem-helpers.h"
+
+G_DEFINE_TYPE (MMModemX22xGsm, mm_modem_x22x_gsm, MM_TYPE_GENERIC_GSM)
+
+MMModem *
+mm_modem_x22x_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin,
+ guint32 vendor,
+ guint32 product)
+{
+ g_return_val_if_fail (device != NULL, NULL);
+ g_return_val_if_fail (driver != NULL, NULL);
+ g_return_val_if_fail (plugin != NULL, NULL);
+
+ return MM_MODEM (g_object_new (MM_TYPE_MODEM_X22X_GSM,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
+ NULL));
+}
+
+/*****************************************************************************/
+
+static gboolean
+parse_syssel_response (GString *response,
+ MMModemGsmAllowedMode *out_mode,
+ GError **error)
+{
+ GRegex *r;
+ GMatchInfo *match_info;
+ char *str;
+ gint mode = -1;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (response != NULL, FALSE);
+ g_return_val_if_fail (out_mode != NULL, FALSE);
+
+ r = g_regex_new ("\\+SYSSEL:\\s*(\\d),(\\d),(\\d),(\\d)", G_REGEX_UNGREEDY, 0, NULL);
+ if (!r) {
+ g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Internal error parsing mode/tech response");
+ return FALSE;
+ }
+
+ if (!g_regex_match_full (r, response->str, response->len, 0, 0, &match_info, NULL)) {
+ g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Failed to parse mode/tech response");
+ goto out;
+ }
+
+ str = g_match_info_fetch (match_info, 3);
+ mode = atoi (str);
+ g_free (str);
+
+ g_match_info_free (match_info);
+
+ if (mode < 0 || mode > 2) {
+ g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Failed to parse mode/tech response");
+ goto out;
+ }
+
+ if (out_mode) {
+ if (mode == 0)
+ *out_mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+ else if (mode == 1)
+ *out_mode = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY;
+ else if (mode == 2)
+ *out_mode = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY;
+ else
+ *out_mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+ }
+ success = TRUE;
+
+out:
+ g_regex_unref (r);
+ return success;
+}
+
+static void
+get_allowed_mode_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemGsmAllowedMode mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (!info->error) {
+ parse_syssel_response (response, &mode, &info->error);
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mode), NULL);
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_allowed_mode (MMGenericGsm *gsm,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
+
+ info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (gsm, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (port, "+SYSSEL?", 3, get_allowed_mode_done, info);
+}
+
+static void
+set_allowed_mode_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ info->error = mm_modem_check_removed (info->modem, error);
+ mm_callback_info_schedule (info);
+}
+
+static void
+set_allowed_mode (MMGenericGsm *gsm,
+ MMModemGsmAllowedMode mode,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
+ char *command = NULL;
+
+ info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (gsm, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ switch (mode) {
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY:
+ command = "+SYSSEL=,1,0";
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY:
+ command = "+SYSSEL=,2,0";
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_ANY:
+ default:
+ command = "+SYSSEL=,0,0";
+ break;
+ }
+
+ mm_at_serial_port_queue_command (port, command, 3, set_allowed_mode_done, info);
+}
+
+/*****************************************************************************/
+
+static void
+mm_modem_x22x_gsm_init (MMModemX22xGsm *self)
+{
+}
+
+static void
+mm_modem_x22x_gsm_class_init (MMModemX22xGsmClass *klass)
+{
+ MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
+
+ mm_modem_x22x_gsm_parent_class = g_type_class_peek_parent (klass);
+
+ gsm_class->set_allowed_mode = set_allowed_mode;
+ gsm_class->get_allowed_mode = get_allowed_mode;
+}
+
diff --git a/plugins/mm-modem-x22x-gsm.h b/plugins/mm-modem-x22x-gsm.h
new file mode 100644
index 0000000..61cc14d
--- /dev/null
+++ b/plugins/mm-modem-x22x-gsm.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 - 2010 Red Hat, Inc.
+ */
+
+#ifndef MM_MODEM_X22X_GSM_H
+#define MM_MODEM_X22X_GSM_H
+
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_X22X_GSM (mm_modem_x22x_gsm_get_type ())
+#define MM_MODEM_X22X_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_X22X_GSM, MMModemX22xGsm))
+#define MM_MODEM_X22X_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_X22X_GSM, MMModemX22xGsmClass))
+#define MM_IS_MODEM_X22X_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_X22X_GSM))
+#define MM_IS_MODEM_X22X_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_X22X_GSM))
+#define MM_MODEM_X22X_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_X22X_GSM, MMModemX22xGsmClass))
+
+typedef struct {
+ MMGenericGsm parent;
+} MMModemX22xGsm;
+
+typedef struct {
+ MMGenericGsmClass parent;
+} MMModemX22xGsmClass;
+
+GType mm_modem_x22x_gsm_get_type (void);
+
+MMModem *mm_modem_x22x_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin,
+ guint32 vendor,
+ guint32 product);
+
+#endif /* MM_MODEM_X22X_H */
diff --git a/plugins/mm-modem-zte.c b/plugins/mm-modem-zte.c
index ba8a1db..c447c58 100644
--- a/plugins/mm-modem-zte.c
+++ b/plugins/mm-modem-zte.c
@@ -24,11 +24,17 @@
#include "mm-errors.h"
#include "mm-callback-info.h"
#include "mm-modem-helpers.h"
+#include "mm-modem-simple.h"
+#include "mm-modem-icera.h"
static void modem_init (MMModem *modem_class);
+static void modem_icera_init (MMModemIcera *icera_class);
+static void modem_simple_init (MMModemSimple *simple_class);
G_DEFINE_TYPE_EXTENDED (MMModemZte, mm_modem_zte, MM_TYPE_GENERIC_GSM, 0,
- G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init))
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_ICERA, modem_icera_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simple_init))
#define MM_MODEM_ZTE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_ZTE, MMModemZtePrivate))
@@ -36,12 +42,15 @@ typedef struct {
gboolean init_retried;
guint32 cpms_tries;
guint cpms_timeout;
+ gboolean is_icera;
} MMModemZtePrivate;
MMModem *
mm_modem_zte_new (const char *device,
const char *driver,
- const char *plugin)
+ const char *plugin,
+ guint32 vendor,
+ guint32 product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -51,6 +60,8 @@ mm_modem_zte_new (const char *device,
MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
@@ -145,9 +156,15 @@ get_allowed_mode (MMGenericGsm *gsm,
MMModemUIntFn callback,
gpointer user_data)
{
+ MMModemZte *self = MM_MODEM_ZTE (gsm);
MMCallbackInfo *info;
MMAtSerialPort *port;
+ if (MM_MODEM_ZTE_GET_PRIVATE (self)->is_icera) {
+ mm_modem_icera_get_allowed_mode (MM_MODEM_ICERA (self), callback, user_data);
+ return;
+ }
+
info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data);
port = mm_generic_gsm_get_best_at_port (gsm, &info->error);
@@ -179,11 +196,17 @@ set_allowed_mode (MMGenericGsm *gsm,
MMModemFn callback,
gpointer user_data)
{
+ MMModemZte *self = MM_MODEM_ZTE (gsm);
MMCallbackInfo *info;
MMAtSerialPort *port;
char *command;
int cm_mode = 0, pref_acq = 0;
+ if (MM_MODEM_ZTE_GET_PRIVATE (self)->is_icera) {
+ mm_modem_icera_set_allowed_mode (MM_MODEM_ICERA (self), mode, callback, user_data);
+ return;
+ }
+
info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data);
port = mm_generic_gsm_get_best_at_port (gsm, &info->error);
@@ -244,16 +267,22 @@ get_act_request_done (MMAtSerialPort *port,
}
static void
-get_access_technology (MMGenericGsm *modem,
+get_access_technology (MMGenericGsm *gsm,
MMModemUIntFn callback,
gpointer user_data)
{
+ MMModemZte *self = MM_MODEM_ZTE (gsm);
MMAtSerialPort *port;
MMCallbackInfo *info;
- info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
+ if (MM_MODEM_ZTE_GET_PRIVATE (self)->is_icera) {
+ mm_modem_icera_get_access_technology (MM_MODEM_ICERA (self), callback, user_data);
+ return;
+ }
- port = mm_generic_gsm_get_best_at_port (modem, &info->error);
+ info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (gsm, &info->error);
if (!port) {
mm_callback_info_schedule (info);
return;
@@ -262,6 +291,21 @@ get_access_technology (MMGenericGsm *modem,
mm_at_serial_port_queue_command (port, "+ZPAS?", 3, get_act_request_done, info);
}
+static void
+do_disconnect (MMGenericGsm *gsm,
+ gint cid,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMModemZte *self = MM_MODEM_ZTE (gsm);
+ MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (self);
+
+ if (priv->is_icera)
+ mm_modem_icera_do_disconnect (gsm, cid, callback, user_data);
+ else
+ MM_GENERIC_GSM_CLASS (mm_modem_zte_parent_class)->do_disconnect (gsm, cid, callback, user_data);
+}
+
/*****************************************************************************/
/* Modem class override functions */
/*****************************************************************************/
@@ -310,6 +354,10 @@ cpms_try_done (MMAtSerialPort *port,
}
}
+ /* Turn on unsolicited network state messages */
+ if (priv->is_icera)
+ mm_modem_icera_change_unsolicited_messages (MM_MODEM_ICERA (info->modem), TRUE);
+
mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
}
@@ -321,6 +369,8 @@ init_modem_done (MMAtSerialPort *port,
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ mm_at_serial_port_queue_command (port, "E0", 5, NULL, NULL);
+
/* Attempt to disable floods of "+ZUSIMR:2" unsolicited responses that
* eventually fill up the device's buffers and make it crash. Normally
* done during probing, but if the device has a PIN enabled it won't
@@ -334,13 +384,33 @@ static void enable_flash_done (MMSerialPort *port,
gpointer user_data);
static void
+icera_check_cb (MMModem *modem,
+ guint32 result,
+ GError *error,
+ gpointer user_data)
+{
+ if (!error) {
+ MMModemZte *self = MM_MODEM_ZTE (user_data);
+ MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (self);
+
+ if (result) {
+ priv->is_icera = TRUE;
+ g_object_set (G_OBJECT (modem),
+ MM_MODEM_IP_METHOD, MM_MODEM_IP_METHOD_STATIC,
+ NULL);
+ }
+ }
+}
+
+static void
pre_init_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (info->modem);
+ MMModemZte *self = MM_MODEM_ZTE (info->modem);
+ MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (self);
if (error) {
/* Retry the init string one more time; the modem sometimes throws it away */
@@ -349,9 +419,10 @@ pre_init_done (MMAtSerialPort *port,
priv->init_retried = TRUE;
enable_flash_done (MM_SERIAL_PORT (port), NULL, user_data);
} else
- mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
+ mm_generic_gsm_enable_complete (MM_GENERIC_GSM (self), error, info);
} else {
/* Finish the initialization */
+ mm_modem_icera_is_icera (MM_MODEM_ICERA (self), icera_check_cb, self);
mm_at_serial_port_queue_command (port, "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1;", 10, init_modem_done, info);
}
}
@@ -383,21 +454,112 @@ do_enable (MMGenericGsm *modem, MMModemFn callback, gpointer user_data)
mm_serial_port_flash (MM_SERIAL_PORT (primary), 100, FALSE, enable_flash_done, info);
}
+/*****************************************************************************/
+
+typedef struct {
+ MMModem *modem;
+ MMModemFn callback;
+ gpointer user_data;
+} DisableInfo;
+
+static void
+disable_unsolicited_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+
+{
+ MMModem *parent_modem_iface;
+ DisableInfo *info = user_data;
+
+ parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (info->modem));
+ parent_modem_iface->disable (info->modem, info->callback, info->user_data);
+ g_free (info);
+}
+
static void
disable (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (modem);
- MMModem *parent_modem_iface;
+ MMAtSerialPort *primary;
+ DisableInfo *info;
priv->init_retried = FALSE;
- /* Do the normal disable stuff */
- parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem));
- parent_modem_iface->disable (modem, callback, user_data);
+ info = g_malloc0 (sizeof (DisableInfo));
+ info->callback = callback;
+ info->user_data = user_data;
+ info->modem = modem;
+
+ primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
+ /* Turn off unsolicited responses */
+ if (priv->is_icera) {
+ mm_modem_icera_cleanup (MM_MODEM_ICERA (modem));
+ mm_modem_icera_change_unsolicited_messages (MM_MODEM_ICERA (modem), FALSE);
+ }
+
+ /* Random command to ensure unsolicited message disable completes */
+ mm_at_serial_port_queue_command (primary, "E0", 5, disable_unsolicited_done, info);
+}
+
+/*****************************************************************************/
+
+static void
+do_connect (MMModem *modem,
+ const char *number,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMModem *parent_iface;
+
+ if (MM_MODEM_ZTE_GET_PRIVATE (modem)->is_icera)
+ mm_modem_icera_do_connect (MM_MODEM_ICERA (modem), number, callback, user_data);
+ else {
+ parent_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem));
+ parent_iface->connect (MM_MODEM (modem), number, callback, user_data);
+ }
+}
+
+static void
+get_ip4_config (MMModem *modem,
+ MMModemIp4Fn callback,
+ gpointer user_data)
+{
+ MMModem *parent_iface;
+
+ if (MM_MODEM_ZTE_GET_PRIVATE (modem)->is_icera) {
+ mm_modem_icera_get_ip4_config (MM_MODEM_ICERA (modem), callback, user_data);
+ } else {
+ parent_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem));
+ parent_iface->get_ip4_config (MM_MODEM (modem), callback, user_data);
+ }
+}
+
+/*****************************************************************************/
+
+static void
+simple_connect (MMModemSimple *simple,
+ GHashTable *properties,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (simple);
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemSimple *parent_iface;
+
+ if (priv->is_icera)
+ mm_modem_icera_simple_connect (MM_MODEM_ICERA (simple), properties);
+
+ parent_iface = g_type_interface_peek_parent (MM_MODEM_SIMPLE_GET_INTERFACE (simple));
+ parent_iface->connect (MM_MODEM_SIMPLE (simple), properties, callback, info);
}
+/*****************************************************************************/
+
static gboolean
grab_port (MMModem *modem,
const char *subsys,
@@ -447,6 +609,9 @@ grab_port (MMModem *modem,
regex = g_regex_new ("\\r\\n\\+ZEND\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
g_regex_unref (regex);
+
+ /* Add Icera-specific handlers */
+ mm_modem_icera_register_unsolicted_handlers (MM_MODEM_ICERA (gsm), MM_AT_SERIAL_PORT (port));
}
return !!port;
@@ -458,10 +623,24 @@ static void
modem_init (MMModem *modem_class)
{
modem_class->disable = disable;
+ modem_class->connect = do_connect;
+ modem_class->get_ip4_config = get_ip4_config;
modem_class->grab_port = grab_port;
}
static void
+modem_icera_init (MMModemIcera *icera_class)
+{
+ mm_modem_icera_prepare (icera_class);
+}
+
+static void
+modem_simple_init (MMModemSimple *class)
+{
+ class->connect = simple_connect;
+}
+
+static void
mm_modem_zte_init (MMModemZte *self)
{
}
@@ -474,6 +653,10 @@ dispose (GObject *object)
if (priv->cpms_timeout)
g_source_remove (priv->cpms_timeout);
+
+ mm_modem_icera_cleanup (MM_MODEM_ICERA (self));
+
+ G_OBJECT_CLASS (mm_modem_zte_parent_class)->dispose (object);
}
static void
@@ -487,6 +670,7 @@ mm_modem_zte_class_init (MMModemZteClass *klass)
object_class->dispose = dispose;
gsm_class->do_enable = do_enable;
+ gsm_class->do_disconnect = do_disconnect;
gsm_class->set_allowed_mode = set_allowed_mode;
gsm_class->get_allowed_mode = get_allowed_mode;
gsm_class->get_access_technology = get_access_technology;
diff --git a/plugins/mm-modem-zte.h b/plugins/mm-modem-zte.h
index 112bae0..f2f068b 100644
--- a/plugins/mm-modem-zte.h
+++ b/plugins/mm-modem-zte.h
@@ -38,6 +38,8 @@ GType mm_modem_zte_get_type (void);
MMModem *mm_modem_zte_new (const char *device,
const char *driver,
- const char *plugin);
+ const char *plugin,
+ guint32 vendor,
+ guint32 product);
#endif /* MM_MODEM_ZTE_H */
diff --git a/plugins/mm-plugin-anydata.c b/plugins/mm-plugin-anydata.c
index 94f4f10..76df673 100644
--- a/plugins/mm-plugin-anydata.c
+++ b/plugins/mm-plugin-anydata.c
@@ -110,6 +110,7 @@ grab_port (MMPluginBase *base,
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
+ guint16 vendor = 0, product = 0;
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
@@ -129,6 +130,11 @@ grab_port (MMPluginBase *base,
return NULL;
}
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
if (!existing) {
if (caps & CAP_CDMA) {
@@ -136,7 +142,9 @@ grab_port (MMPluginBase *base,
mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (MM_PLUGIN (base)),
!!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856),
- !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A));
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A),
+ vendor,
+ product);
}
if (modem) {
diff --git a/plugins/mm-plugin-generic.c b/plugins/mm-plugin-generic.c
index cdf2c66..a27704b 100644
--- a/plugins/mm-plugin-generic.c
+++ b/plugins/mm-plugin-generic.c
@@ -10,7 +10,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details:
*
- * Copyright (C) 2008 - 2009 Dan Williams <dcbw@redhat.com>
+ * Copyright (C) 2008 - 2010 Dan Williams <dcbw@redhat.com>
*/
#include <string.h>
@@ -31,6 +31,7 @@
#include "mm-generic-cdma.h"
#include "mm-errors.h"
#include "mm-serial-parsers.h"
+#include "mm-log.h"
G_DEFINE_TYPE (MMPluginGeneric, mm_plugin_generic, MM_TYPE_PLUGIN_BASE)
@@ -112,6 +113,7 @@ grab_port (MMPluginBase *base,
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path, *driver;
guint32 caps;
+ guint16 vendor = 0, product = 0;
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
@@ -126,26 +128,35 @@ grab_port (MMPluginBase *base,
g_set_error (error, 0, 0, "Could not get port's sysfs file.");
return NULL;
} else {
- g_message ("%s: (%s/%s) WARNING: missing udev 'device' file",
- mm_plugin_get_name (MM_PLUGIN (base)),
- subsys,
- name);
+ mm_warn ("%s: (%s/%s) WARNING: missing udev 'device' file",
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ subsys,
+ name);
}
}
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
if (!existing) {
- if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
- modem = mm_generic_gsm_new (sysfs_path,
- mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
- } else if (caps & CAP_CDMA) {
+ if (caps & CAP_CDMA) {
modem = mm_generic_cdma_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (MM_PLUGIN (base)),
!!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856),
- !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A));
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A),
+ vendor,
+ product);
+ } else if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_generic_gsm_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
}
if (modem) {
diff --git a/plugins/mm-plugin-gobi.c b/plugins/mm-plugin-gobi.c
index fbe3878..36771d1 100644
--- a/plugins/mm-plugin-gobi.c
+++ b/plugins/mm-plugin-gobi.c
@@ -106,6 +106,7 @@ grab_port (MMPluginBase *base,
MMModem *modem = NULL;
const char *name, *subsys, *sysfs_path;
guint32 caps;
+ guint16 vendor = 0, product = 0;
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
@@ -113,19 +114,28 @@ grab_port (MMPluginBase *base,
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
if (!existing) {
if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
modem = mm_modem_gobi_gsm_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
} else if (caps & CAP_CDMA) {
modem = mm_generic_cdma_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (MM_PLUGIN (base)),
!!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856),
- !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A));
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A),
+ vendor,
+ product);
}
if (modem) {
diff --git a/plugins/mm-plugin-hso.c b/plugins/mm-plugin-hso.c
index dc0a8fc..7b71932 100644
--- a/plugins/mm-plugin-hso.c
+++ b/plugins/mm-plugin-hso.c
@@ -105,6 +105,7 @@ grab_port (MMPluginBase *base,
const char *name, *subsys, *sysfs_path;
char *devfile;
guint32 caps;
+ guint16 vendor = 0, product = 0;
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
@@ -112,6 +113,11 @@ grab_port (MMPluginBase *base,
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
devfile = g_strdup (g_udev_device_get_device_file (port));
if (!devfile) {
if (!strcmp (subsys, "net")) {
@@ -139,7 +145,9 @@ grab_port (MMPluginBase *base,
if (!existing) {
modem = mm_modem_hso_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
if (modem) {
if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error)) {
g_object_unref (modem);
diff --git a/plugins/mm-plugin-huawei.c b/plugins/mm-plugin-huawei.c
index 2993689..f1590ca 100644
--- a/plugins/mm-plugin-huawei.c
+++ b/plugins/mm-plugin-huawei.c
@@ -27,6 +27,7 @@
#include "mm-modem-huawei-cdma.h"
#include "mm-serial-parsers.h"
#include "mm-at-serial-port.h"
+#include "mm-log.h"
G_DEFINE_TYPE (MMPluginHuawei, mm_plugin_huawei, MM_TYPE_PLUGIN_BASE)
@@ -239,19 +240,19 @@ supports_port (MMPluginBase *base,
info->id = g_timeout_add_seconds (7, probe_secondary_timeout, task);
- g_object_set_data_full (G_OBJECT (task), TAG_SUPPORTS_INFO,
- info, huawei_supports_info_destroy);
-
if (!mm_serial_port_open (MM_SERIAL_PORT (info->serial), &error)) {
- g_warning ("%s: (Huawei) %s: couldn't open serial port: (%d) %s",
- __func__, name,
- error ? error->code : -1,
- error && error->message ? error->message : "(unknown)");
+ mm_warn ("(Huawei) %s: couldn't open serial port: (%d) %s",
+ name,
+ error ? error->code : -1,
+ error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
huawei_supports_info_destroy (info);
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
+ g_object_set_data_full (G_OBJECT (task), TAG_SUPPORTS_INFO,
+ info, huawei_supports_info_destroy);
+
return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
}
@@ -268,7 +269,7 @@ grab_port (MMPluginBase *base,
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
- guint16 product = 0;
+ guint16 vendor = 0, product = 0;
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
@@ -282,7 +283,7 @@ grab_port (MMPluginBase *base,
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
- if (!mm_plugin_base_get_device_ids (base, subsys, name, NULL, &product)) {
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
g_set_error (error, 0, 0, "Could not get modem product ID.");
return NULL;
}
@@ -292,14 +293,18 @@ grab_port (MMPluginBase *base,
if (!existing) {
if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
modem = mm_modem_huawei_gsm_new (sysfs_path,
- mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
} else if (caps & CAP_CDMA) {
modem = mm_modem_huawei_cdma_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (MM_PLUGIN (base)),
!!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856),
- !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A));
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A),
+ vendor,
+ product);
}
if (modem) {
diff --git a/plugins/mm-plugin-linktop.c b/plugins/mm-plugin-linktop.c
new file mode 100644
index 0000000..411f9cc
--- /dev/null
+++ b/plugins/mm-plugin-linktop.c
@@ -0,0 +1,164 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <gmodule.h>
+#include "mm-plugin-linktop.h"
+#include "mm-modem-linktop.h"
+
+G_DEFINE_TYPE (MMPluginLinktop, mm_plugin_linktop, MM_TYPE_PLUGIN_BASE)
+
+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_LINKTOP,
+ MM_PLUGIN_BASE_NAME, "Linktop",
+ NULL));
+}
+
+/*****************************************************************************/
+
+static guint32
+get_level_for_capabilities (guint32 capabilities)
+{
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 10;
+ return 0;
+}
+
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
+{
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
+}
+
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
+{
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *subsys, *name;
+ guint16 vendor = 0;
+
+ /* Can't do anything with non-serial ports */
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (vendor != 0x230d)
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
+ mm_plugin_base_supports_task_complete (task, level);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ }
+
+ /* Otherwise kick off a probe */
+ if (mm_plugin_base_probe_port (base, task, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+}
+
+static MMModem *
+grab_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task,
+ GError **error)
+{
+ GUdevDevice *port = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
+ guint32 caps;
+ guint16 vendor = 0, product = 0;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ devfile = g_udev_device_get_device_file (port);
+ if (!devfile) {
+ g_set_error (error, 0, 0, "Could not get port's sysfs file.");
+ return NULL;
+ }
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
+ caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
+ sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_modem_linktop_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
+ }
+
+ if (modem) {
+ if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error)) {
+ g_object_unref (modem);
+ return NULL;
+ }
+ }
+ } else if (get_level_for_capabilities (caps)) {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error))
+ return NULL;
+ }
+
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_linktop_init (MMPluginLinktop *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_linktop_class_init (MMPluginLinktopClass *klass)
+{
+ MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
+
+ pb_class->supports_port = supports_port;
+ pb_class->grab_port = grab_port;
+}
diff --git a/plugins/mm-plugin-linktop.h b/plugins/mm-plugin-linktop.h
new file mode 100644
index 0000000..b904725
--- /dev/null
+++ b/plugins/mm-plugin-linktop.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_PLUGIN_LINKTOP_H
+#define MM_PLUGIN_LINKTOP_H
+
+#include "mm-plugin-base.h"
+
+#define MM_TYPE_PLUGIN_LINKTOP (mm_plugin_linktop_get_type ())
+#define MM_PLUGIN_LINKTOP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_LINKTOP, MMPluginLinktop))
+#define MM_PLUGIN_LINKTOP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_LINKTOP, MMPluginLinktopClass))
+#define MM_IS_PLUGIN_LINKTOP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_LINKTOP))
+#define MM_IS_PLUGIN_LINKTOP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_LINKTOP))
+#define MM_PLUGIN_LINKTOP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_LINKTOP, MMPluginLinktopClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginLinktop;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginLinktopClass;
+
+GType mm_plugin_linktop_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_LINKTOP_H */
diff --git a/plugins/mm-plugin-longcheer.c b/plugins/mm-plugin-longcheer.c
index dbbe186..e63ff4e 100644
--- a/plugins/mm-plugin-longcheer.c
+++ b/plugins/mm-plugin-longcheer.c
@@ -114,6 +114,7 @@ grab_port (MMPluginBase *base,
const char *name, *subsys, *sysfs_path;
guint32 caps;
MMPortType ptype = MM_PORT_TYPE_UNKNOWN;
+ guint16 vendor = 0, product = 0;
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
@@ -138,19 +139,28 @@ grab_port (MMPluginBase *base,
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
if (!existing) {
if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
modem = mm_modem_longcheer_gsm_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
} else if (caps & CAP_CDMA) {
modem = mm_generic_cdma_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (MM_PLUGIN (base)),
!!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856),
- !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A));
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A),
+ vendor,
+ product);
}
if (modem) {
diff --git a/plugins/mm-plugin-mbm.c b/plugins/mm-plugin-mbm.c
index 5554d84..6684ff9 100644
--- a/plugins/mm-plugin-mbm.c
+++ b/plugins/mm-plugin-mbm.c
@@ -84,7 +84,7 @@ supports_port (MMPluginBase *base,
client = g_udev_client_new (sys);
if (!client) {
- g_warning ("mbm: could not get udev client.");
+ g_warn_if_fail (client != NULL);
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
}
@@ -132,6 +132,7 @@ grab_port (MMPluginBase *base,
MMModem *modem = NULL;
const char *name, *subsys, *sysfs_path;
guint32 caps;
+ guint16 vendor = 0, product = 0;
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
@@ -143,11 +144,18 @@ grab_port (MMPluginBase *base,
if (!(caps & MM_PLUGIN_BASE_PORT_CAP_GSM) && strcmp (subsys, "net"))
return NULL;
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
if (!existing) {
modem = mm_modem_mbm_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
if (modem) {
if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error)) {
g_object_unref (modem);
diff --git a/plugins/mm-plugin-moto-c.c b/plugins/mm-plugin-moto-c.c
index d798af4..21b737e 100644
--- a/plugins/mm-plugin-moto-c.c
+++ b/plugins/mm-plugin-moto-c.c
@@ -105,6 +105,7 @@ grab_port (MMPluginBase *base,
GUdevDevice *port = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path;
+ guint16 vendor = 0, product = 0;
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
@@ -118,11 +119,18 @@ grab_port (MMPluginBase *base,
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
if (!existing) {
modem = mm_modem_moto_c_gsm_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
if (modem) {
if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error)) {
diff --git a/plugins/mm-plugin-nokia.c b/plugins/mm-plugin-nokia.c
index 2d0d6af..938f8c5 100644
--- a/plugins/mm-plugin-nokia.c
+++ b/plugins/mm-plugin-nokia.c
@@ -109,6 +109,7 @@ grab_port (MMPluginBase *base,
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
+ guint16 vendor = 0, product = 0;
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
@@ -122,19 +123,28 @@ grab_port (MMPluginBase *base,
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
if (!existing) {
if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
modem = mm_modem_nokia_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
} else if (caps & CAP_CDMA) {
modem = mm_generic_cdma_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (MM_PLUGIN (base)),
!!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856),
- !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A));
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A),
+ vendor,
+ product);
}
if (modem) {
diff --git a/plugins/mm-plugin-novatel.c b/plugins/mm-plugin-novatel.c
index a968836..5384456 100644
--- a/plugins/mm-plugin-novatel.c
+++ b/plugins/mm-plugin-novatel.c
@@ -115,6 +115,7 @@ grab_port (MMPluginBase *base,
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
+ guint16 vendor = 0, product = 0;
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
@@ -128,19 +129,28 @@ grab_port (MMPluginBase *base,
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
if (!existing) {
if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
modem = mm_modem_novatel_gsm_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
} else if (caps & CAP_CDMA) {
modem = mm_modem_novatel_cdma_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (MM_PLUGIN (base)),
!!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856),
- !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A));
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A),
+ vendor,
+ product);
}
if (modem) {
diff --git a/plugins/mm-plugin-option.c b/plugins/mm-plugin-option.c
index 101f9bd..ab2bd3d 100644
--- a/plugins/mm-plugin-option.c
+++ b/plugins/mm-plugin-option.c
@@ -107,6 +107,7 @@ grab_port (MMPluginBase *base,
guint32 caps;
int usbif;
MMPortType ptype = MM_PORT_TYPE_SECONDARY;
+ guint16 vendor = 0, product = 0;
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
@@ -129,13 +130,20 @@ grab_port (MMPluginBase *base,
if (usbif == 0)
ptype = MM_PORT_TYPE_PRIMARY;
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
if (!existing) {
if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
modem = mm_modem_option_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
}
if (modem) {
diff --git a/plugins/mm-plugin-sierra.c b/plugins/mm-plugin-sierra.c
index 8ace653..b7367ab 100644
--- a/plugins/mm-plugin-sierra.c
+++ b/plugins/mm-plugin-sierra.c
@@ -90,17 +90,28 @@ supports_port (MMPluginBase *base,
{
GUdevDevice *port;
guint32 cached = 0, level;
- const char *driver;
+ const char *driver, *subsys;
/* Can't do anything with non-serial ports */
port = mm_plugin_base_supports_task_get_port (task);
- if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ if (!port)
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
driver = mm_plugin_base_supports_task_get_driver (task);
- if (!driver || strcmp (driver, "sierra"))
+ if (!driver || (strcmp (driver, "sierra") && strcmp (driver, "sierra_net")))
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ subsys = g_udev_device_get_subsystem (port);
+ g_assert (subsys);
+ if (!strcmp (subsys, "net")) {
+ /* Can't grab the net port until we know whether this is a CDMA or GSM device */
+ if (!existing)
+ return MM_PLUGIN_SUPPORTS_PORT_DEFER;
+
+ mm_plugin_base_supports_task_complete (task, 10);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
+
if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
level = get_level_for_capabilities (cached);
if (level) {
@@ -125,19 +136,14 @@ grab_port (MMPluginBase *base,
{
GUdevDevice *port = NULL;
MMModem *modem = NULL;
- const char *name, *subsys, *devfile, *sysfs_path;
+ const char *name, *subsys, *sysfs_path;
guint32 caps;
MMPortType ptype = MM_PORT_TYPE_UNKNOWN;
+ guint16 vendor = 0, product = 0;
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
- devfile = g_udev_device_get_device_file (port);
- if (!devfile) {
- g_set_error (error, 0, 0, "Could not get port's sysfs file.");
- return NULL;
- }
-
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
@@ -145,19 +151,28 @@ grab_port (MMPluginBase *base,
if (g_object_get_data (G_OBJECT (task), TAG_SIERRA_SECONDARY_PORT))
ptype = MM_PORT_TYPE_SECONDARY;
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
if (!existing) {
if ((caps & MM_PLUGIN_BASE_PORT_CAP_GSM) || (ptype != MM_PORT_TYPE_UNKNOWN)) {
modem = mm_modem_sierra_gsm_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
} else if (caps & CAP_CDMA) {
modem = mm_modem_sierra_cdma_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (MM_PLUGIN (base)),
!!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856),
- !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A));
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A),
+ vendor,
+ product);
}
if (modem) {
@@ -166,7 +181,16 @@ grab_port (MMPluginBase *base,
return NULL;
}
}
- } else if (get_level_for_capabilities (caps) || (ptype != MM_PORT_TYPE_UNKNOWN)) {
+ } else if ( get_level_for_capabilities (caps)
+ || (ptype != MM_PORT_TYPE_UNKNOWN)
+ || (strcmp (subsys, "net") == 0)) {
+
+ /* FIXME: we don't yet know how to activate IP on CDMA devices using
+ * pseudo-ethernet ports.
+ */
+ if (strcmp (subsys, "net") == 0 && MM_IS_MODEM_SIERRA_CDMA (modem))
+ return modem;
+
modem = existing;
if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error))
return NULL;
diff --git a/plugins/mm-plugin-simtech.c b/plugins/mm-plugin-simtech.c
index 3c44873..611d2d2 100644
--- a/plugins/mm-plugin-simtech.c
+++ b/plugins/mm-plugin-simtech.c
@@ -114,6 +114,7 @@ grab_port (MMPluginBase *base,
const char *name, *subsys, *sysfs_path;
guint32 caps;
MMPortType ptype = MM_PORT_TYPE_UNKNOWN;
+ guint16 vendor = 0, product = 0;
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
@@ -138,19 +139,28 @@ grab_port (MMPluginBase *base,
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
if (!existing) {
if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
modem = mm_modem_simtech_gsm_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
} else if (caps & CAP_CDMA) {
modem = mm_generic_cdma_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (MM_PLUGIN (base)),
!!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856),
- !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A));
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A),
+ vendor,
+ product);
}
if (modem) {
diff --git a/plugins/mm-plugin-x22x.c b/plugins/mm-plugin-x22x.c
new file mode 100644
index 0000000..5a8253f
--- /dev/null
+++ b/plugins/mm-plugin-x22x.c
@@ -0,0 +1,192 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 - 2010 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <gmodule.h>
+#include "mm-plugin-x22x.h"
+#include "mm-modem-x22x-gsm.h"
+#include "mm-generic-gsm.h"
+
+G_DEFINE_TYPE (MMPluginX22x, mm_plugin_x22x, MM_TYPE_PLUGIN_BASE)
+
+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_X22X,
+ MM_PLUGIN_BASE_NAME, "X22X",
+ NULL));
+}
+
+/*****************************************************************************/
+
+static guint32
+get_level_for_capabilities (guint32 capabilities)
+{
+ /* These modems have the same vendor ID as a few of the other
+ * Alcatel/TCT/T&A modems, and the longcheer plugin will try to claim them
+ * too. So we provide a higher support level here to make sure this
+ * plugin tries to grab it's supported devices first.
+ */
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 20;
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_QCDM)
+ return 20;
+ return 0;
+}
+
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
+{
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
+}
+
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
+{
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ guint16 vendor = 0;
+ const char *subsys, *name;
+
+ /* Can't do anything with non-serial ports */
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ /* Only TCT/T&A for now */
+ if (vendor != 0x1bbb)
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ /* If the port wasn't tagged, we don't support it */
+ if (!g_udev_device_get_property_as_boolean (port, "ID_MM_X22X_TAGGED"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
+ mm_plugin_base_supports_task_complete (task, level);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ }
+
+ /* Otherwise kick off a probe */
+ if (mm_plugin_base_probe_port (base, task, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+}
+
+static MMModem *
+grab_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task,
+ GError **error)
+{
+ GUdevDevice *port = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *sysfs_path;
+ guint32 caps;
+ MMPortType ptype = MM_PORT_TYPE_UNKNOWN;
+ guint16 vendor = 0, product = 0;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ /* Look for port type hints; just probing can't distinguish which port should
+ * be the data/primary port on these devices. We have to tag them based on
+ * what the Windows .INF files say the port layout should be.
+ */
+ if (g_udev_device_get_property_as_boolean (port, "ID_MM_X22X_PORT_TYPE_MODEM"))
+ ptype = MM_PORT_TYPE_PRIMARY;
+ else if (g_udev_device_get_property_as_boolean (port, "ID_MM_X22X_PORT_TYPE_AUX"))
+ ptype = MM_PORT_TYPE_SECONDARY;
+
+ /* If the device was tagged by the udev rules, then ignore any other ports
+ * to guard against race conditions if a device just happens to show up
+ * with more than two AT-capable ports.
+ */
+ if ( (ptype == MM_PORT_TYPE_UNKNOWN)
+ && g_udev_device_get_property_as_boolean (port, "ID_MM_X22X_TAGGED"))
+ ptype = MM_PORT_TYPE_IGNORED;
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
+ caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
+ sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_modem_x22x_gsm_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
+ }
+
+ if (modem) {
+ if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error)) {
+ g_object_unref (modem);
+ return NULL;
+ }
+ }
+ } else if (get_level_for_capabilities (caps)) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_QCDM)
+ ptype = MM_PORT_TYPE_QCDM;
+
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error))
+ return NULL;
+ }
+
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_x22x_init (MMPluginX22x *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_x22x_class_init (MMPluginX22xClass *klass)
+{
+ MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
+
+ pb_class->supports_port = supports_port;
+ pb_class->grab_port = grab_port;
+}
diff --git a/plugins/mm-plugin-x22x.h b/plugins/mm-plugin-x22x.h
new file mode 100644
index 0000000..227511d
--- /dev/null
+++ b/plugins/mm-plugin-x22x.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 - 2010 Red Hat, Inc.
+ */
+
+#ifndef MM_PLUGIN_X22X_H
+#define MM_PLUGIN_X22X_H
+
+#include "mm-plugin-base.h"
+
+#define MM_TYPE_PLUGIN_X22X (mm_plugin_x22x_get_type ())
+#define MM_PLUGIN_X22X(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_X22X, MMPluginX22x))
+#define MM_PLUGIN_X22X_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_X22X, MMPluginX22xClass))
+#define MM_IS_PLUGIN_X22X(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_X22X))
+#define MM_IS_PLUGIN_X22X_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_X22X))
+#define MM_PLUGIN_X22X_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_X22X, MMPluginX22xClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginX22x;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginX22xClass;
+
+GType mm_plugin_x22x_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_X22X_H */
diff --git a/plugins/mm-plugin-zte.c b/plugins/mm-plugin-zte.c
index e943bbf..bb2ee17 100644
--- a/plugins/mm-plugin-zte.c
+++ b/plugins/mm-plugin-zte.c
@@ -11,7 +11,7 @@
* GNU General Public License for more details:
*
* Copyright (C) 2008 - 2009 Novell, Inc.
- * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 - 2010 Red Hat, Inc.
*/
#include <string.h>
@@ -73,9 +73,6 @@ supports_port (MMPluginBase *base,
/* Can't do anything with non-serial ports */
port = mm_plugin_base_supports_task_get_port (task);
- if (strcmp (g_udev_device_get_subsystem (port), "tty"))
- return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
-
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
@@ -85,6 +82,20 @@ supports_port (MMPluginBase *base,
if (vendor != 0x19d2)
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ if (!strcmp (subsys, "net")) {
+ /* If we don't know the modem's type yet, defer grabbing the port
+ * until we know the type.
+ */
+ if (!existing)
+ return MM_PLUGIN_SUPPORTS_PORT_DEFER;
+
+ mm_plugin_base_supports_task_complete (task, 10);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
+
+ if (strcmp (subsys, "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
level = get_level_for_capabilities (cached);
if (level) {
@@ -121,6 +132,7 @@ grab_port (MMPluginBase *base,
const char *name, *subsys, *sysfs_path;
guint32 caps;
MMPortType ptype = MM_PORT_TYPE_UNKNOWN;
+ guint16 vendor = 0, product = 0;
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
@@ -134,19 +146,28 @@ grab_port (MMPluginBase *base,
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
if (!existing) {
if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
modem = mm_modem_zte_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ vendor,
+ product);
} else if (caps & CAP_CDMA) {
modem = mm_generic_cdma_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (MM_PLUGIN (base)),
!!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856),
- !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A));
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A),
+ vendor,
+ product);
}
if (modem) {
@@ -155,7 +176,7 @@ grab_port (MMPluginBase *base,
return NULL;
}
}
- } else if (get_level_for_capabilities (caps)) {
+ } else if (get_level_for_capabilities (caps) || (!strcmp (subsys, "net"))) {
if (caps & MM_PLUGIN_BASE_PORT_CAP_QCDM)
ptype = MM_PORT_TYPE_QCDM;
diff --git a/policy/org.freedesktop.modem-manager.policy.in b/policy/org.freedesktop.modem-manager.policy.in
index 8719936..ed98f63 100644
--- a/policy/org.freedesktop.modem-manager.policy.in
+++ b/policy/org.freedesktop.modem-manager.policy.in
@@ -54,4 +54,13 @@
</defaults>
</action>
+ <action id="org.freedesktop.ModemManager.USSD">
+ <_description>Query and utilize network information and services</_description>
+ <_message>System policy prevents querying or utilizing network information and services.</_message>
+ <defaults>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>yes</allow_active>
+ </defaults>
+ </action>
+
</policyconfig>
diff --git a/src/77-mm-usb-device-blacklist.rules b/src/77-mm-usb-device-blacklist.rules
index 78a6770..58b0cee 100644
--- a/src/77-mm-usb-device-blacklist.rules
+++ b/src/77-mm-usb-device-blacklist.rules
@@ -62,5 +62,11 @@ ATTRS{idVendor}=="0592", ATTRS{idProduct}=="0002", ENV{ID_MM_DEVICE_IGNORE}="1"
# that isn't blacklisted.
ATTRS{idVendor}=="0830", ATTRS{idProduct}=="0061", ENV{ID_MM_DEVICE_IGNORE}="1"
+# Belkin F5U183 Serial Adapter (unlikely to have a modem behind it)
+ATTRS{idVendor}=="050d", ATTRS{idProduct}=="0103", ENV{ID_MM_DEVICE_IGNORE}="1"
+
+# ATEN Intl UC-232A (Prolific)
+ATTRS{idVendor}=="0557", ATTRS{idProduct}=="2008", ENV{ID_MM_DEVICE_IGNORE}="1"
+
LABEL="mm_usb_device_blacklist_end"
diff --git a/src/80-mm-candidate.rules b/src/80-mm-candidate.rules
new file mode 100644
index 0000000..e99ae3a
--- /dev/null
+++ b/src/80-mm-candidate.rules
@@ -0,0 +1,16 @@
+# do not edit this file, it will be overwritten on update
+
+# Tag any devices that MM might be interested in; if ModemManager is started
+# up right after udev, when MM explicitly requests devices on startup it may
+# get devices that haven't had all rules run yet. Thus, we tag devices we're
+# interested in and when handling devices during MM startup we ignore any
+# that don't have this tag. MM will still get the udev 'add' event for the
+# device a short while later and then process it as normal.
+
+ACTION!="add|change|move", GOTO="mm_candidate_end"
+
+SUBSYSTEM=="tty", ENV{ID_MM_CANDIDATE}="1"
+SUBSYSTEM=="net", ENV{ID_MM_CANDIDATE}="1"
+
+LABEL="mm_candidate_end"
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 2061ae8..e813e7e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,12 +4,13 @@ udevrulesdir = $(UDEV_BASE_DIR)/rules.d
udevrules_DATA = \
77-mm-usb-device-blacklist.rules \
77-mm-pcmcia-device-blacklist.rules \
- 77-mm-platform-serial-whitelist.rules
+ 77-mm-platform-serial-whitelist.rules \
+ 80-mm-candidate.rules
EXTRA_DIST = \
$(udevrules_DATA)
-noinst_LTLIBRARIES = libmodem-helpers.la
+noinst_LTLIBRARIES = libmodem-helpers.la libserial.la
libmodem_helpers_la_CPPFLAGS = \
$(MM_CFLAGS)
@@ -24,6 +25,20 @@ libmodem_helpers_la_SOURCES = \
mm-utils.c \
mm-utils.h
+libserial_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ -I$(top_srcdir)
+
+libserial_la_SOURCES = \
+ mm-port.c \
+ mm-port.h \
+ mm-serial-port.c \
+ mm-serial-port.h \
+ mm-at-serial-port.c \
+ mm-at-serial-port.h \
+ mm-qcdm-serial-port.c \
+ mm-qcdm-serial-port.h
+
sbin_PROGRAMS = modem-manager
modem_manager_CPPFLAGS = \
@@ -41,8 +56,9 @@ modem_manager_LDADD = \
$(MM_LIBS) \
$(GUDEV_LIBS) \
$(top_builddir)/marshallers/libmarshallers.la \
- $(top_builddir)/libqcdm/src/libqcdm.la \
- $(builddir)/libmodem-helpers.la
+ $(builddir)/libmodem-helpers.la \
+ $(builddir)/libserial.la \
+ $(top_builddir)/libqcdm/src/libqcdm.la
if WITH_POLKIT
modem_manager_LDADD += $(POLKIT_LIBS)
@@ -63,12 +79,10 @@ auth_sources += \
mm-auth-provider-polkit.h
endif
-loc_sources = \
- mm-modem-location.c \
- mm-modem-location.h
-
modem_manager_SOURCES = \
main.c \
+ mm-log.c \
+ mm-log.h \
mm-callback-info.c \
mm-callback-info.h \
$(auth_sources) \
@@ -76,14 +90,6 @@ modem_manager_SOURCES = \
mm-manager.h \
mm-modem.c \
mm-modem.h \
- mm-port.c \
- mm-port.h \
- mm-serial-port.c \
- mm-serial-port.h \
- mm-at-serial-port.c \
- mm-at-serial-port.h \
- mm-qcdm-serial-port.c \
- mm-qcdm-serial-port.h \
mm-serial-parsers.c \
mm-serial-parsers.h \
mm-modem-base.c \
@@ -101,37 +107,45 @@ modem_manager_SOURCES = \
mm-modem-gsm-network.h \
mm-modem-gsm-sms.c \
mm-modem-gsm-sms.h \
+ mm-modem-gsm-ussd.c \
+ mm-modem-gsm-ussd.h \
mm-modem-simple.c \
mm-modem-simple.h \
- mm-options.c \
- mm-options.h \
mm-plugin.c \
mm-plugin.h \
mm-plugin-base.c \
mm-plugin-base.h \
mm-properties-changed-signal.c \
- mm-properties-changed-signal.h
+ mm-properties-changed-signal.h \
+ mm-modem-location.c \
+ mm-modem-location.h
-mm-manager-glue.h: $(top_srcdir)/introspection/mm-manager.xml
- dbus-binding-tool --prefix=mm_manager --mode=glib-server --output=$@ $<
+mm-manager-glue.h: $(top_srcdir)/introspection/org.freedesktop.ModemManager.xml
+ $(AM_V_GEN) 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=$@ $<
+mm-modem-glue.h: $(top_srcdir)/introspection/org.freedesktop.ModemManager.Modem.xml
+ $(AM_V_GEN) dbus-binding-tool --prefix=mm_modem --mode=glib-server --output=$@ $<
-mm-modem-simple-glue.h: $(top_srcdir)/introspection/mm-modem-simple.xml
- dbus-binding-tool --prefix=mm_modem_simple --mode=glib-server --output=$@ $<
+mm-modem-simple-glue.h: $(top_srcdir)/introspection/org.freedesktop.ModemManager.Modem.Simple.xml
+ $(AM_V_GEN) dbus-binding-tool --prefix=mm_modem_simple --mode=glib-server --output=$@ $<
-mm-modem-cdma-glue.h: $(top_srcdir)/introspection/mm-modem-cdma.xml
- dbus-binding-tool --prefix=mm_modem_cdma --mode=glib-server --output=$@ $<
+mm-modem-cdma-glue.h: $(top_srcdir)/introspection/org.freedesktop.ModemManager.Modem.Cdma.xml
+ $(AM_V_GEN) dbus-binding-tool --prefix=mm_modem_cdma --mode=glib-server --output=$@ $<
-mm-modem-gsm-card-glue.h: $(top_srcdir)/introspection/mm-modem-gsm-card.xml
- dbus-binding-tool --prefix=mm_modem_gsm_card --mode=glib-server --output=$@ $<
+mm-modem-gsm-card-glue.h: $(top_srcdir)/introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml
+ $(AM_V_GEN) dbus-binding-tool --prefix=mm_modem_gsm_card --mode=glib-server --output=$@ $<
-mm-modem-gsm-network-glue.h: $(top_srcdir)/introspection/mm-modem-gsm-network.xml
- dbus-binding-tool --prefix=mm_modem_gsm_network --mode=glib-server --output=$@ $<
+mm-modem-gsm-network-glue.h: $(top_srcdir)/introspection/org.freedesktop.ModemManager.Modem.Gsm.Network.xml
+ $(AM_V_GEN) dbus-binding-tool --prefix=mm_modem_gsm_network --mode=glib-server --output=$@ $<
-mm-modem-gsm-sms-glue.h: $(top_srcdir)/introspection/mm-modem-gsm-sms.xml
- dbus-binding-tool --prefix=mm_modem_gsm_sms --mode=glib-server --output=$@ $<
+mm-modem-gsm-sms-glue.h: $(top_srcdir)/introspection/org.freedesktop.ModemManager.Modem.Gsm.SMS.xml
+ $(AM_V_GEN) dbus-binding-tool --prefix=mm_modem_gsm_sms --mode=glib-server --output=$@ $<
+
+mm-modem-gsm-ussd-glue.h: $(top_srcdir)/introspection/org.freedesktop.ModemManager.Modem.Gsm.Ussd.xml
+ $(AM_V_GEN) dbus-binding-tool --prefix=mm_modem_gsm_ussd --mode=glib-server --output=$@ $<
+
+mm-properties-changed-glue.h: $(top_srcdir)/introspection/org.freedesktop.DBus.Properties.xml
+ $(AM_V_GEN) dbus-binding-tool --prefix=mm_properties_changed --mode=glib-server --output=$@ $<
BUILT_SOURCES = \
mm-manager-glue.h \
@@ -140,17 +154,15 @@ BUILT_SOURCES = \
mm-modem-cdma-glue.h \
mm-modem-gsm-card-glue.h \
mm-modem-gsm-network-glue.h \
- mm-modem-gsm-sms-glue.h
+ mm-modem-gsm-sms-glue.h \
+ mm-modem-gsm-ussd-glue.h \
+ mm-properties-changed-glue.h
-if WITH_LOCATION_API
-mm-modem-location-glue.h: $(top_srcdir)/introspection/mm-modem-location.xml
- dbus-binding-tool --prefix=mm_modem_location --mode=glib-server --output=$@ $<
+mm-modem-location-glue.h: $(top_srcdir)/introspection/org.freedesktop.ModemManager.Modem.Location.xml
+ $(AM_V_GEN) dbus-binding-tool --prefix=mm_modem_location --mode=glib-server --output=$@ $<
modem_manager_SOURCES += $(loc_sources)
BUILT_SOURCES += mm-modem-location-glue.h
-else
-EXTRA_DIST += $(loc_sources)
-endif
CLEANFILES = $(BUILT_SOURCES)
diff --git a/src/main.c b/src/main.c
index 72fa6dc..0f8119e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -11,7 +11,7 @@
* GNU General Public License for more details:
*
* Copyright (C) 2008 - 2009 Novell, Inc.
- * Copyright (C) 2009 - 2010 Red Hat, Inc.
+ * Copyright (C) 2009 - 2011 Red Hat, Inc.
*/
#include <config.h>
@@ -21,8 +21,10 @@
#include <unistd.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
+#include <stdlib.h>
+
#include "mm-manager.h"
-#include "mm-options.h"
+#include "mm-log.h"
#if !defined(MM_DIST_VERSION)
# define MM_DIST_VERSION VERSION
@@ -34,9 +36,9 @@ static void
mm_signal_handler (int signo)
{
if (signo == SIGUSR1)
- mm_options_set_debug (!mm_options_debug ());
+ mm_log_usr1 ();
else if (signo == SIGINT || signo == SIGTERM) {
- g_message ("Caught signal %d, shutting down...", signo);
+ mm_info ("Caught signal %d, shutting down...", signo);
if (loop)
g_main_loop_quit (loop);
else
@@ -60,64 +62,9 @@ setup_signals (void)
}
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)
{
- g_message ("disconnected from the system bus, exiting.");
+ mm_warn ("disconnected from the system bus, exiting.");
g_main_loop_quit (loop);
}
@@ -139,16 +86,16 @@ create_dbus_proxy (DBusGConnection *bus)
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);
+ mm_warn ("Could not acquire the %s service.\n"
+ " Message: '%s'", MM_DBUS_SERVICE, err->message);
g_error_free (err);
g_object_unref (proxy);
proxy = NULL;
} else if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- g_warning ("Could not acquire the " MM_DBUS_SERVICE
- " service as it is already taken. Return: %d",
- request_name_result);
+ mm_warn ("Could not acquire the " MM_DBUS_SERVICE
+ " service as it is already taken. Return: %d",
+ request_name_result);
g_object_unref (proxy);
proxy = NULL;
@@ -175,17 +122,49 @@ main (int argc, char *argv[])
DBusGProxy *proxy;
MMManager *manager;
GError *err = NULL;
+ GOptionContext *opt_ctx;
guint id;
+ const char *log_level = NULL, *log_file = NULL;
+ gboolean debug = FALSE, show_ts = FALSE, rel_ts = FALSE;
+
+ GOptionEntry entries[] = {
+ { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Output to console rather than syslog", NULL },
+ { "log-level", 0, 0, G_OPTION_ARG_STRING, &log_level, "Log level: one of [ERR, WARN, INFO, DEBUG]", "INFO" },
+ { "log-file", 0, 0, G_OPTION_ARG_STRING, &log_file, "Path to log file", NULL },
+ { "timestamps", 0, 0, G_OPTION_ARG_NONE, &show_ts, "Show timestamps in log output", NULL },
+ { "relative-timestamps", 0, 0, G_OPTION_ARG_NONE, &rel_ts, "Use relative timestamps (from MM start)", NULL },
+ { NULL }
+ };
- mm_options_parse (argc, argv);
g_type_init ();
- setup_signals ();
+ 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 (!mm_options_debug ())
- logging_setup ();
+ if (!g_option_context_parse (opt_ctx, &argc, &argv, &err)) {
+ g_warning ("%s\n", err->message);
+ g_error_free (err);
+ exit (1);
+ }
- g_message ("ModemManager (version " MM_DIST_VERSION ") starting...");
+ g_option_context_free (opt_ctx);
+
+ if (debug) {
+ log_level = "DEBUG";
+ if (!show_ts && !rel_ts)
+ show_ts = TRUE;
+ }
+
+ if (!mm_log_setup (log_level, log_file, show_ts, rel_ts, &err)) {
+ g_warning ("Failed to set up logging: %s", err->message);
+ g_error_free (err);
+ exit (1);
+ }
+
+ setup_signals ();
+
+ mm_info ("ModemManager (version " MM_DIST_VERSION ") starting...");
bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
if (!bus) {
@@ -196,6 +175,17 @@ main (int argc, char *argv[])
return -1;
}
+#ifndef HAVE_DBUS_GLIB_DISABLE_LEGACY_PROP_ACCESS
+#error HAVE_DBUS_GLIB_DISABLE_LEGACY_PROP_ACCESS not defined
+#endif
+
+#if HAVE_DBUS_GLIB_DISABLE_LEGACY_PROP_ACCESS
+ /* Ensure that non-exported properties don't leak out, and that the
+ * introspection 'access' permissions are respected.
+ */
+ dbus_glib_global_set_disable_legacy_property_access ();
+#endif
+
proxy = create_dbus_proxy (bus);
if (!proxy)
return -1;
@@ -224,7 +214,7 @@ main (int argc, char *argv[])
g_object_unref (proxy);
dbus_g_connection_unref (bus);
- logging_shutdown ();
+ mm_log_shutdown ();
return 0;
}
diff --git a/src/mm-at-serial-port.c b/src/mm-at-serial-port.c
index 068450d..30da3a3 100644
--- a/src/mm-at-serial-port.c
+++ b/src/mm-at-serial-port.c
@@ -23,7 +23,7 @@
#include "mm-at-serial-port.h"
#include "mm-errors.h"
-#include "mm-options.h"
+#include "mm-log.h"
G_DEFINE_TYPE (MMAtSerialPort, mm_at_serial_port, MM_TYPE_SERIAL_PORT)
@@ -273,7 +273,6 @@ debug_log (MMSerialPort *port, const char *prefix, const char *buf, gsize len)
{
static GString *debug = NULL;
const char *s;
- GTimeVal tv;
if (!debug)
debug = g_string_sized_new (256);
@@ -290,18 +289,13 @@ debug_log (MMSerialPort *port, const char *prefix, const char *buf, gsize len)
else if (*s == '\n')
g_string_append (debug, "<LF>");
else
- g_string_append_printf (debug, "\\%d", *s);
+ g_string_append_printf (debug, "\\%u", (guint8) (*s & 0xFF));
s++;
}
g_string_append_c (debug, '\'');
- g_get_current_time (&tv);
- g_debug ("<%ld.%ld> (%s): %s",
- tv.tv_sec,
- tv.tv_usec,
- mm_port_get_device (MM_PORT (port)),
- debug->str);
+ mm_dbg ("(%s): %s", mm_port_get_device (MM_PORT (port)), debug->str);
g_string_truncate (debug, 0);
}
diff --git a/src/mm-auth-provider-polkit.c b/src/mm-auth-provider-polkit.c
index c457eaf..2cd4a8a 100644
--- a/src/mm-auth-provider-polkit.c
+++ b/src/mm-auth-provider-polkit.c
@@ -15,6 +15,7 @@
#include <polkit/polkit.h>
+#include <config.h>
#include "mm-auth-request-polkit.h"
#include "mm-auth-provider-polkit.h"
@@ -72,19 +73,39 @@ real_create_request (MMAuthProvider *provider,
/*****************************************************************************/
+/* Fix for polkit 0.97 and later */
+#if !HAVE_POLKIT_AUTHORITY_GET_SYNC
+static inline PolkitAuthority *
+polkit_authority_get_sync (GCancellable *cancellable, GError **error)
+{
+ PolkitAuthority *authority;
+
+ authority = polkit_authority_get ();
+ if (!authority)
+ g_set_error (error, 0, 0, "failed to get the PolicyKit authority");
+ return authority;
+}
+#endif
+
static void
mm_auth_provider_polkit_init (MMAuthProviderPolkit *self)
{
MMAuthProviderPolkitPrivate *priv = MM_AUTH_PROVIDER_POLKIT_GET_PRIVATE (self);
+ GError *error = NULL;
- priv->authority = polkit_authority_get ();
+ priv->authority = polkit_authority_get_sync (NULL, &error);
if (priv->authority) {
priv->auth_changed_id = g_signal_connect (priv->authority,
"changed",
G_CALLBACK (pk_authority_changed_cb),
self);
- } else
- g_warning ("%s: failed to create PolicyKit authority.", __func__);
+ } else {
+ g_warning ("%s: failed to create PolicyKit authority: (%d) %s",
+ __func__,
+ error ? error->code : -1,
+ error && error->message ? error->message : "(unknown)");
+ g_clear_error (&error);
+ }
}
static void
diff --git a/src/mm-auth-provider.h b/src/mm-auth-provider.h
index 26ff340..32082f0 100644
--- a/src/mm-auth-provider.h
+++ b/src/mm-auth-provider.h
@@ -26,6 +26,7 @@
#define MM_AUTHORIZATION_DEVICE_CONTROL "org.freedesktop.ModemManager.Device.Control"
#define MM_AUTHORIZATION_CONTACTS "org.freedesktop.ModemManager.Contacts"
#define MM_AUTHORIZATION_SMS "org.freedesktop.ModemManager.SMS"
+#define MM_AUTHORIZATION_USSD "org.freedesktop.ModemManager.USSD"
#define MM_AUTHORIZATION_LOCATION "org.freedesktop.ModemManager.Location"
/******************/
diff --git a/src/mm-charsets.c b/src/mm-charsets.c
index c75c3a9..d2b9a66 100644
--- a/src/mm-charsets.c
+++ b/src/mm-charsets.c
@@ -109,7 +109,7 @@ charset_iconv_from (MMModemCharset charset)
gboolean
mm_modem_charset_byte_array_append (GByteArray *array,
- const char *string,
+ const char *utf8,
gboolean quoted,
MMModemCharset charset)
{
@@ -119,22 +119,16 @@ mm_modem_charset_byte_array_append (GByteArray *array,
gsize written = 0;
g_return_val_if_fail (array != NULL, FALSE);
- g_return_val_if_fail (string != NULL, FALSE);
+ g_return_val_if_fail (utf8 != NULL, FALSE);
iconv_to = charset_iconv_to (charset);
g_return_val_if_fail (iconv_to != NULL, FALSE);
- converted = g_convert (string,
- g_utf8_strlen (string, -1),
- iconv_to,
- "UTF-8",
- NULL,
- &written,
- &error);
+ converted = g_convert (utf8, -1, iconv_to, "UTF-8", NULL, &written, &error);
if (!converted) {
if (error) {
g_warning ("%s: failed to convert '%s' to %s character set: (%d) %s",
- __func__, string, iconv_to,
+ __func__, utf8, iconv_to,
error->code, error->message);
g_error_free (error);
}
@@ -154,9 +148,10 @@ mm_modem_charset_byte_array_append (GByteArray *array,
char *
mm_modem_charset_hex_to_utf8 (const char *src, MMModemCharset charset)
{
- char *unconverted;
+ char *unconverted, *converted;
const char *iconv_from;
gsize unconverted_len = 0;
+ GError *error = NULL;
g_return_val_if_fail (src != NULL, NULL);
g_return_val_if_fail (charset != MM_MODEM_CHARSET_UNKNOWN, NULL);
@@ -170,6 +165,340 @@ mm_modem_charset_hex_to_utf8 (const char *src, MMModemCharset charset)
if (charset == MM_MODEM_CHARSET_UTF8 || charset == MM_MODEM_CHARSET_IRA)
return unconverted;
- return g_convert (unconverted, unconverted_len, "UTF-8//TRANSLIT", iconv_from, NULL, NULL, NULL);
+ converted = g_convert (unconverted, unconverted_len,
+ "UTF-8//TRANSLIT", iconv_from,
+ NULL, NULL, &error);
+ if (!converted || error) {
+ g_clear_error (&error);
+ g_free (unconverted);
+ converted = NULL;
+ }
+
+ return converted;
+}
+
+
+/* GSM 03.38 encoding conversion stuff */
+
+#define GSM_DEF_ALPHABET_SIZE 128
+#define GSM_EXT_ALPHABET_SIZE 10
+
+typedef struct GsmUtf8Mapping {
+ gchar chars[3];
+ guint8 len;
+ guint8 gsm; /* only used for extended GSM charset */
+} GsmUtf8Mapping;
+
+#define ONE(a) { {a, 0x00, 0x00}, 1, 0 }
+#define TWO(a, b) { {a, b, 0x00}, 2, 0 }
+
+/**
+ * gsm_def_utf8_alphabet:
+ *
+ * Mapping from GSM default alphabet to UTF-8.
+ *
+ * ETSI GSM 03.38, version 6.0.1, section 6.2.1; Default alphabet. Mapping to UCS-2.
+ * Mapping according to http://unicode.org/Public/MAPPINGS/ETSI/GSM0338.TXT
+ */
+static const GsmUtf8Mapping gsm_def_utf8_alphabet[GSM_DEF_ALPHABET_SIZE] = {
+ /* @ £ $ ¥ */
+ ONE(0x40), TWO(0xc2, 0xa3), ONE(0x24), TWO(0xc2, 0xa5),
+ /* è é ù ì */
+ TWO(0xc3, 0xa8), TWO(0xc3, 0xa9), TWO(0xc3, 0xb9), TWO(0xc3, 0xac),
+ /* ò Ç \n Ø */
+ TWO(0xc3, 0xb2), TWO(0xc3, 0x87), ONE(0x0a), TWO(0xc3, 0x98),
+ /* ø \r Å å */
+ TWO(0xc3, 0xb8), ONE(0x0d), TWO(0xc3, 0x85), TWO(0xc3, 0xa5),
+ /* Δ _ Φ Γ */
+ TWO(0xce, 0x94), ONE(0x5f), TWO(0xce, 0xa6), TWO(0xce, 0x93),
+ /* Λ Ω Π Ψ */
+ TWO(0xce, 0x9b), TWO(0xce, 0xa9), TWO(0xce, 0xa0), TWO(0xce, 0xa8),
+ /* Σ Θ Ξ Escape Code */
+ TWO(0xce, 0xa3), TWO(0xce, 0x98), TWO(0xce, 0x9e), ONE(0xa0),
+ /* Æ æ ß É */
+ TWO(0xc3, 0x86), TWO(0xc3, 0xa6), TWO(0xc3, 0x9f), TWO(0xc3, 0x89),
+ /* ' ' ! " # */
+ ONE(0x20), ONE(0x21), ONE(0x22), ONE(0x23),
+ /* ¤ % & ' */
+ TWO(0xc2, 0xa4), ONE(0x25), ONE(0x26), ONE(0x27),
+ /* ( ) * + */
+ ONE(0x28), ONE(0x29), ONE(0x2a), ONE(0x2b),
+ /* , - . / */
+ ONE(0x2c), ONE(0x2d), ONE(0x2e), ONE(0x2f),
+ /* 0 1 2 3 */
+ ONE(0x30), ONE(0x31), ONE(0x32), ONE(0x33),
+ /* 4 5 6 7 */
+ ONE(0x34), ONE(0x35), ONE(0x36), ONE(0x37),
+ /* 8 9 : ; */
+ ONE(0x38), ONE(0x39), ONE(0x3a), ONE(0x3b),
+ /* < = > ? */
+ ONE(0x3c), ONE(0x3d), ONE(0x3e), ONE(0x3f),
+ /* ¡ A B C */
+ TWO(0xc2, 0xa1), ONE(0x41), ONE(0x42), ONE(0x43),
+ /* D E F G */
+ ONE(0x44), ONE(0x45), ONE(0x46), ONE(0x47),
+ /* H I J K */
+ ONE(0x48), ONE(0x49), ONE(0x4a), ONE(0x4b),
+ /* L M N O */
+ ONE(0x4c), ONE(0x4d), ONE(0x4e), ONE(0x4f),
+ /* P Q R S */
+ ONE(0x50), ONE(0x51), ONE(0x52), ONE(0x53),
+ /* T U V W */
+ ONE(0x54), ONE(0x55), ONE(0x56), ONE(0x57),
+ /* X Y Z Ä */
+ ONE(0x58), ONE(0x59), ONE(0x5a), TWO(0xc3, 0x84),
+ /* Ö Ñ Ü § */
+ TWO(0xc3, 0x96), TWO(0xc3, 0x91), TWO(0xc3, 0x9c), TWO(0xc2, 0xa7),
+ /* ¿ a b c */
+ TWO(0xc2, 0xbf), ONE(0x61), ONE(0x62), ONE(0x63),
+ /* d e f g */
+ ONE(0x64), ONE(0x65), ONE(0x66), ONE(0x67),
+ /* h i j k */
+ ONE(0x68), ONE(0x69), ONE(0x6a), ONE(0x6b),
+ /* l m n o */
+ ONE(0x6c), ONE(0x6d), ONE(0x6e), ONE(0x6f),
+ /* p q r s */
+ ONE(0x70), ONE(0x71), ONE(0x72), ONE(0x73),
+ /* t u v w */
+ ONE(0x74), ONE(0x75), ONE(0x76), ONE(0x77),
+ /* x y z ä */
+ ONE(0x78), ONE(0x79), ONE(0x7a), TWO(0xc3, 0xa4),
+ /* ö ñ ü à */
+ TWO(0xc3, 0xb6), TWO(0xc3, 0xb1), TWO(0xc3, 0xbc), TWO(0xc3, 0xa0)
+};
+
+static guint8
+gsm_def_char_to_utf8 (const guint8 gsm, guint8 out_utf8[2])
+{
+ g_return_val_if_fail (gsm < GSM_DEF_ALPHABET_SIZE, 0);
+ memcpy (&out_utf8[0], &gsm_def_utf8_alphabet[gsm].chars[0], gsm_def_utf8_alphabet[gsm].len);
+ return gsm_def_utf8_alphabet[gsm].len;
+}
+
+static gboolean
+utf8_to_gsm_def_char (const char *utf8, guint32 len, guint8 *out_gsm)
+{
+ int i;
+
+ if (len > 0 && len < 4) {
+ for (i = 0; i < GSM_DEF_ALPHABET_SIZE; i++) {
+ if (gsm_def_utf8_alphabet[i].len == len) {
+ if (memcmp (&gsm_def_utf8_alphabet[i].chars[0], utf8, len) == 0) {
+ *out_gsm = i;
+ return TRUE;
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+#define EONE(a, g) { {a, 0x00, 0x00}, 1, g }
+#define ETHR(a, b, c, g) { {a, b, c}, 3, g }
+
+/**
+ * gsm_ext_utf8_alphabet:
+ *
+ * Mapping from GSM extended alphabet to UTF-8.
+ *
+ */
+static const GsmUtf8Mapping gsm_ext_utf8_alphabet[GSM_EXT_ALPHABET_SIZE] = {
+ /* form feed ^ { } */
+ EONE(0x0c, 0x0a), EONE(0x5e, 0x14), EONE(0x7b, 0x28), EONE(0x7d, 0x29),
+ /* \ [ ~ ] */
+ EONE(0x5c, 0x2f), EONE(0x5b, 0x3c), EONE(0x7e, 0x3d), EONE(0x5d, 0x3e),
+ /* | € */
+ EONE(0x7c, 0x40), ETHR(0xe2, 0x82, 0xac, 0x65)
+};
+
+#define GSM_ESCAPE_CHAR 0x1b
+
+static guint8
+gsm_ext_char_to_utf8 (const guint8 gsm, guint8 out_utf8[3])
+{
+ int i;
+
+ for (i = 0; i < GSM_EXT_ALPHABET_SIZE; i++) {
+ if (gsm == gsm_ext_utf8_alphabet[i].gsm) {
+ memcpy (&out_utf8[0], &gsm_ext_utf8_alphabet[i].chars[0], gsm_ext_utf8_alphabet[i].len);
+ return gsm_ext_utf8_alphabet[i].len;
+ }
+ }
+ return 0;
+}
+
+static gboolean
+utf8_to_gsm_ext_char (const char *utf8, guint32 len, guint8 *out_gsm)
+{
+ int i;
+
+ if (len > 0 && len < 4) {
+ for (i = 0; i < GSM_EXT_ALPHABET_SIZE; i++) {
+ if (gsm_ext_utf8_alphabet[i].len == len) {
+ if (memcmp (&gsm_ext_utf8_alphabet[i].chars[0], utf8, len) == 0) {
+ *out_gsm = gsm_ext_utf8_alphabet[i].gsm;
+ return TRUE;
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+guint8 *
+mm_charset_gsm_unpacked_to_utf8 (const guint8 *gsm, guint32 len)
+{
+ int i;
+ GByteArray *utf8;
+
+ g_return_val_if_fail (gsm != NULL, NULL);
+ g_return_val_if_fail (len < 4096, NULL);
+
+ /* worst case initial length */
+ utf8 = g_byte_array_sized_new (len * 2 + 1);
+
+ for (i = 0; i < len; i++) {
+ guint8 uchars[4];
+ guint8 ulen;
+
+ if (gsm[i] == GSM_ESCAPE_CHAR) {
+ /* Extended alphabet, decode next char */
+ ulen = gsm_ext_char_to_utf8 (gsm[i+1], uchars);
+ if (ulen)
+ i += 1;
+ } else {
+ /* Default alphabet */
+ ulen = gsm_def_char_to_utf8 (gsm[i], uchars);
+ }
+
+ if (ulen)
+ g_byte_array_append (utf8, &uchars[0], ulen);
+ else
+ g_byte_array_append (utf8, (guint8 *) "?", 1);
+ }
+
+ g_byte_array_append (utf8, (guint8 *) "\0", 1); /* NULL terminator */
+ return g_byte_array_free (utf8, FALSE);
+}
+
+guint8 *
+mm_charset_utf8_to_unpacked_gsm (const char *utf8, guint32 *out_len)
+{
+ GByteArray *gsm;
+ const char *c = utf8, *next = c;
+ static const guint8 gesc = GSM_ESCAPE_CHAR;
+ int i = 0;
+
+ g_return_val_if_fail (utf8 != NULL, NULL);
+ g_return_val_if_fail (out_len != NULL, NULL);
+ g_return_val_if_fail (g_utf8_validate (utf8, -1, NULL), NULL);
+
+ /* worst case initial length */
+ gsm = g_byte_array_sized_new (g_utf8_strlen (utf8, -1) * 2 + 1);
+
+ if (*utf8 == 0x00) {
+ /* Zero-length string */
+ g_byte_array_append (gsm, (guint8 *) "\0", 1);
+ *out_len = 0;
+ return g_byte_array_free (gsm, FALSE);
+ }
+
+ while (next && *next) {
+ guint8 gch = 0x3f; /* 0x3f == '?' */
+
+ next = g_utf8_next_char (c);
+
+ /* Try escaped chars first, then default alphabet */
+ if (utf8_to_gsm_ext_char (c, next - c, &gch)) {
+ /* Add the escape char */
+ g_byte_array_append (gsm, &gesc, 1);
+ g_byte_array_append (gsm, &gch, 1);
+ } else if (utf8_to_gsm_def_char (c, next - c, &gch))
+ g_byte_array_append (gsm, &gch, 1);
+
+ c = next;
+ i++;
+ }
+
+ *out_len = gsm->len;
+ return g_byte_array_free (gsm, FALSE);
+}
+
+guint8 *
+gsm_unpack (const guint8 *gsm,
+ guint32 gsm_len,
+ guint8 start_offset, /* in _bits_ */
+ guint32 *out_unpacked_len)
+{
+ GByteArray *unpacked;
+ int i, nchars;
+
+ nchars = ((gsm_len * 8) - start_offset) / 7;
+ unpacked = g_byte_array_sized_new (nchars + 1);
+
+ for (i = 0; i < nchars; i++) {
+ guint8 bits_here, bits_in_next, octet, offset, c;
+ guint32 start_bit;
+
+ start_bit = start_offset + (i * 7); /* Overall bit offset of char in buffer */
+ offset = start_bit % 8; /* Offset to start of char in this byte */
+ bits_here = offset ? (8 - offset) : 7;
+ bits_in_next = 7 - bits_here;
+
+ /* Grab bits in the current byte */
+ octet = gsm[start_bit / 8];
+ c = (octet >> offset) & (0xFF >> (8 - bits_here));
+
+ /* Grab any bits that spilled over to next byte */
+ if (bits_in_next) {
+ octet = gsm[(start_bit / 8) + 1];
+ c |= (octet & (0xFF >> (8 - bits_in_next))) << bits_here;
+ }
+ g_byte_array_append (unpacked, &c, 1);
+ }
+
+ *out_unpacked_len = unpacked->len;
+ return g_byte_array_free (unpacked, FALSE);
+}
+
+guint8 *
+gsm_pack (const guint8 *src,
+ guint32 src_len,
+ guint8 start_offset,
+ guint32 *out_packed_len)
+{
+ GByteArray *packed;
+ guint8 c, add_last = 0;
+ int i;
+
+ packed = g_byte_array_sized_new (src_len);
+
+ for (i = 0, c = 0; i < src_len; i++) {
+ guint8 bits_here, offset;
+ guint32 start_bit;
+
+ start_bit = start_offset + (i * 7); /* Overall bit offset of char in buffer */
+ offset = start_bit % 8; /* Offset to start of char in this byte */
+ bits_here = offset ? (8 - offset) : 7;
+
+ c |= (src[i] & 0x7F) << offset;
+ if (offset) {
+ /* Add this packed byte */
+ g_byte_array_append (packed, &c, 1);
+ c = add_last = 0;
+ }
+
+ /* Pack the rest of this char into the next byte */
+ if (bits_here != 7) {
+ c = (src[i] & 0x7F) >> bits_here;
+ add_last = 1;
+ }
+ }
+ if (add_last)
+ g_byte_array_append (packed, &c, 1);
+
+ *out_packed_len = packed->len;
+ return g_byte_array_free (packed, FALSE);
}
diff --git a/src/mm-charsets.h b/src/mm-charsets.h
index 5fa3406..661052d 100644
--- a/src/mm-charsets.h
+++ b/src/mm-charsets.h
@@ -39,7 +39,7 @@ MMModemCharset mm_modem_charset_from_string (const char *string);
* UTF-8 encoded.
*/
gboolean mm_modem_charset_byte_array_append (GByteArray *array,
- const char *string,
+ const char *utf8,
gboolean quoted,
MMModemCharset charset);
@@ -48,5 +48,19 @@ gboolean mm_modem_charset_byte_array_append (GByteArray *array,
*/
char *mm_modem_charset_hex_to_utf8 (const char *src, MMModemCharset charset);
+guint8 *mm_charset_utf8_to_unpacked_gsm (const char *utf8, guint32 *out_len);
+
+guint8 *mm_charset_gsm_unpacked_to_utf8 (const guint8 *gsm, guint32 len);
+
+guint8 *gsm_unpack (const guint8 *gsm,
+ guint32 gsm_len,
+ guint8 start_offset, /* in bits */
+ guint32 *out_unpacked_len);
+
+guint8 *gsm_pack (const guint8 *src,
+ guint32 src_len,
+ guint8 start_offset, /* in bits */
+ guint32 *out_packed_len);
+
#endif /* MM_CHARSETS_H */
diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c
index 9fe897f..0a95e7b 100644
--- a/src/mm-generic-cdma.c
+++ b/src/mm-generic-cdma.c
@@ -30,6 +30,7 @@
#include "mm-serial-parsers.h"
#include "mm-modem-helpers.h"
#include "libqcdm/src/commands.h"
+#include "mm-log.h"
#define MM_GENERIC_CDMA_PREV_STATE_TAG "prev-state"
@@ -68,6 +69,8 @@ typedef struct {
guint poll_id;
+ char *meid;
+
MMModemCdmaRegistrationState cdma_1x_reg_state;
MMModemCdmaRegistrationState evdo_reg_state;
@@ -95,7 +98,9 @@ mm_generic_cdma_new (const char *device,
const char *driver,
const char *plugin,
gboolean evdo_rev0,
- gboolean evdo_revA)
+ gboolean evdo_revA,
+ guint vendor,
+ guint product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -107,6 +112,8 @@ mm_generic_cdma_new (const char *device,
MM_MODEM_PLUGIN, plugin,
MM_GENERIC_CDMA_EVDO_REV0, evdo_rev0,
MM_GENERIC_CDMA_EVDO_REVA, evdo_revA,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
@@ -162,6 +169,47 @@ initial_esn_check (MMGenericCdma *self)
}
}
+static void
+get_info_cb (MMModem *modem,
+ const char *manufacturer,
+ const char *model,
+ const char *version,
+ GError *error,
+ gpointer user_data)
+{
+ /* Base class handles saving the info for us */
+ if (modem)
+ mm_serial_port_close (MM_SERIAL_PORT (MM_GENERIC_CDMA_GET_PRIVATE (modem)->primary));
+}
+
+static void
+initial_info_check (MMGenericCdma *self)
+{
+ GError *error = NULL;
+ MMGenericCdmaPrivate *priv;
+
+ g_return_if_fail (MM_IS_GENERIC_CDMA (self));
+ priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
+
+ g_return_if_fail (priv->primary != NULL);
+
+ if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) {
+ /* Make sure echoing is off */
+ mm_at_serial_port_queue_command (priv->primary, "E0", 3, NULL, NULL);
+ mm_modem_base_get_card_info (MM_MODEM_BASE (self),
+ priv->primary,
+ NULL,
+ get_info_cb,
+ NULL);
+ } else {
+ g_warning ("%s: failed to open serial port: (%d) %s",
+ __func__,
+ error ? error->code : -1,
+ error && error->message ? error->message : "(unknown)");
+ g_clear_error (&error);
+ }
+}
+
static gboolean
owns_port (MMModem *modem, const char *subsys, const char *name)
{
@@ -215,6 +263,9 @@ mm_generic_cdma_grab_port (MMGenericCdma *self,
g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE);
}
+ /* Get the modem's general info */
+ initial_info_check (self);
+
/* Get modem's ESN number */
initial_esn_check (self);
@@ -315,6 +366,15 @@ mm_generic_cdma_get_best_at_port (MMGenericCdma *self, GError **error)
return priv->secondary;
}
+MMQcdmSerialPort *
+mm_generic_cdma_get_best_qcdm_port (MMGenericCdma *self, GError **error)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (MM_IS_GENERIC_CDMA (self), NULL);
+
+ return MM_GENERIC_CDMA_GET_PRIVATE (self)->qcdm;
+}
+
/*****************************************************************************/
void
@@ -552,25 +612,6 @@ out:
}
static void
-enable_error_reporting_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMGenericCdma *self = MM_GENERIC_CDMA (info->modem);
-
- /* Just ignore errors, see comment in init_done() */
- if (error)
- g_warning ("Your CDMA modem does not support +CMEE command");
-
- if (MM_GENERIC_CDMA_GET_CLASS (self)->post_enable)
- MM_GENERIC_CDMA_GET_CLASS (self)->post_enable (self, enable_all_done, info);
- else
- enable_all_done (MM_MODEM (self), NULL, info);
-}
-
-static void
init_done (MMAtSerialPort *port,
GString *response,
GError *error,
@@ -586,12 +627,17 @@ init_done (MMAtSerialPort *port,
info->error = g_error_copy (error);
mm_callback_info_schedule (info);
} else {
- /* Try to enable better error reporting. My experience so far indicates
- there's some CDMA modems that does not support that.
- FIXME: It's mandatory by spec, so it really shouldn't be optional. Figure
- out which CDMA modems have problems with it and implement plugin for them.
- */
- mm_at_serial_port_queue_command (port, "+CMEE=1", 3, enable_error_reporting_done, user_data);
+ MMGenericCdma *self = MM_GENERIC_CDMA (info->modem);
+
+ /* Try enabling better error reporting on CDMA devices, but few
+ * actually support +CMEE as it's more of a GSM command.
+ */
+ mm_at_serial_port_queue_command (port, "+CMEE=1", 3, NULL, NULL);
+
+ if (MM_GENERIC_CDMA_GET_CLASS (self)->post_enable)
+ MM_GENERIC_CDMA_GET_CLASS (self)->post_enable (self, enable_all_done, info);
+ else
+ enable_all_done (MM_MODEM (self), NULL, info);
}
}
@@ -1002,7 +1048,7 @@ get_signal_quality (MMModemCdma *modem,
at_port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (modem), &info->error);
if (!at_port && !priv->qcdm) {
- g_message ("Returning saved signal quality %d", priv->cdma1x_quality);
+ mm_dbg ("Returning saved signal quality %d", priv->cdma1x_quality);
mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->cdma1x_quality), NULL);
mm_callback_info_schedule (info);
return;
@@ -1481,15 +1527,22 @@ reg_query_speri_done (MMAtSerialPort *port,
if (!p || !mm_cdma_parse_eri (p, &roam, NULL, NULL))
goto done;
- /* Change the 1x and EVDO registration states to roaming if they were
- * anything other than UNKNOWN.
- */
if (roam) {
+ /* Change the 1x and EVDO registration states to roaming if they were
+ * anything other than UNKNOWN.
+ */
if (mm_generic_cdma_query_reg_state_get_callback_1x_state (info))
mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING);
if (mm_generic_cdma_query_reg_state_get_callback_evdo_state (info))
mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING);
+ } else {
+ /* Change 1x and/or EVDO registration state to home if home/roaming wasn't previously known */
+ if (mm_generic_cdma_query_reg_state_get_callback_1x_state (info) == MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED)
+ mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_HOME);
+
+ if (mm_generic_cdma_query_reg_state_get_callback_evdo_state (info) == MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED)
+ mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_HOME);
}
done:
@@ -1541,6 +1594,12 @@ real_query_registration_state (MMGenericCdma *self,
port = mm_generic_cdma_get_best_at_port (self, &info->error);
if (!port) {
+ /* If we can't get an AT port, but less specific registration checks
+ * were successful, just use that and don't return an error.
+ */
+ if ( cur_cdma_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
+ || cur_evdo_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)
+ g_clear_error (&info->error);
mm_callback_info_schedule (info);
return;
}
@@ -1658,58 +1717,79 @@ error:
}
static void
-reg_cmstate_cb (MMQcdmSerialPort *port,
- GByteArray *response,
- GError *error,
- gpointer user_data)
+reg_hdrstate_cb (MMQcdmSerialPort *port,
+ GByteArray *response,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = user_data;
- MMAtSerialPort *at_port;
- QCDMResult *result;
- guint32 opmode = 0, sysmode = 0;
+ QCDMResult *result = NULL;
+ guint32 sysmode;
MMModemCdmaRegistrationState cdma_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
MMModemCdmaRegistrationState evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
+ MMAtSerialPort *at_port;
+ gboolean evdo_registered = FALSE;
if (error)
goto error;
- /* Parse the response */
- result = qcdm_cmd_cm_subsys_state_info_result ((const char *) response->data, response->len, &info->error);
- if (!result)
- goto error;
+ sysmode = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "sysmode"));
- qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_OPERATING_MODE, &opmode);
- qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SYSTEM_MODE, &sysmode);
- qcdm_result_unref (result);
+ /* Get HDR subsystem state to determine EVDO registration when in 1X mode */
+ result = qcdm_cmd_hdr_subsys_state_info_result ((const char *) response->data,
+ response->len,
+ NULL);
+ if (result) {
+ guint8 session_state = QCDM_CMD_HDR_SUBSYS_STATE_INFO_SESSION_STATE_CLOSED;
+ guint8 almp_state = QCDM_CMD_HDR_SUBSYS_STATE_INFO_ALMP_STATE_INACTIVE;
+ guint8 hybrid_mode = 0;
- if (opmode == QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_ONLINE) {
- switch (sysmode) {
- case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_CDMA:
- cdma_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
- break;
- case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_HDR:
- evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
- break;
- case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_AMPS:
- case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_NO_SERVICE:
- case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_WCDMA:
- default:
- break;
- }
+ if ( qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_SESSION_STATE, &session_state)
+ && qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_ALMP_STATE, &almp_state)
+ && qcdm_result_get_uint8 (result, QCDM_CMD_HDR_SUBSYS_STATE_INFO_ITEM_HDR_HYBRID_MODE, &hybrid_mode)) {
- if (cdma_state || evdo_state) {
- /* Device is registered to something; see if the subclass has a
- * better idea of whether we're roaming or not and what the
- * access technology is.
+ /* EVDO state is registered if the HDR subsystem is registered, and
+ * we're in hybrid mode, and the Call Manager system mode is
+ * CDMA.
*/
- if (MM_GENERIC_CDMA_GET_CLASS (info->modem)->query_registration_state) {
- MM_GENERIC_CDMA_GET_CLASS (info->modem)->query_registration_state (MM_GENERIC_CDMA (info->modem),
- cdma_state,
- evdo_state,
- subclass_reg_query_done,
- info);
- return;
- }
+ if ( hybrid_mode
+ && session_state == QCDM_CMD_HDR_SUBSYS_STATE_INFO_SESSION_STATE_OPEN
+ && ( almp_state == QCDM_CMD_HDR_SUBSYS_STATE_INFO_ALMP_STATE_IDLE
+ || almp_state == QCDM_CMD_HDR_SUBSYS_STATE_INFO_ALMP_STATE_CONNECTED))
+ evdo_registered = TRUE;
+ }
+
+ qcdm_result_unref (result);
+ }
+
+ switch (sysmode) {
+ case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_CDMA:
+ cdma_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
+ if (evdo_registered)
+ evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
+ break;
+ case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_HDR:
+ evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
+ break;
+ case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_AMPS:
+ case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_NO_SERVICE:
+ case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_WCDMA:
+ default:
+ break;
+ }
+
+ if (cdma_state || evdo_state) {
+ /* Device is registered to something; see if the subclass has a
+ * better idea of whether we're roaming or not and what the
+ * access technology is.
+ */
+ if (MM_GENERIC_CDMA_GET_CLASS (info->modem)->query_registration_state) {
+ MM_GENERIC_CDMA_GET_CLASS (info->modem)->query_registration_state (MM_GENERIC_CDMA (info->modem),
+ cdma_state,
+ evdo_state,
+ subclass_reg_query_done,
+ info);
+ return;
}
}
@@ -1728,6 +1808,59 @@ error:
}
static void
+reg_cmstate_cb (MMQcdmSerialPort *port,
+ GByteArray *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ MMAtSerialPort *at_port = NULL;
+ QCDMResult *result = NULL;
+ guint32 opmode = 0, sysmode = 0;
+ GError *qcdm_error = NULL;
+
+ /* Parse the response */
+ if (!error)
+ result = qcdm_cmd_cm_subsys_state_info_result ((const char *) response->data, response->len, &qcdm_error);
+
+ if (!result) {
+ /* If there was some error, fall back to use +CAD like we did before QCDM */
+ if (info->modem)
+ at_port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (info->modem), &info->error);
+ else
+ info->error = g_error_copy (qcdm_error);
+
+ if (at_port)
+ mm_at_serial_port_queue_command (at_port, "+CAD?", 3, get_analog_digital_done, info);
+ else
+ mm_callback_info_schedule (info);
+ g_clear_error (&qcdm_error);
+ return;
+ }
+
+ qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_OPERATING_MODE, &opmode);
+ qcdm_result_get_uint32 (result, QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_SYSTEM_MODE, &sysmode);
+ qcdm_result_unref (result);
+
+ if (opmode == QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_ONLINE) {
+ GByteArray *hdrstate;
+
+ mm_callback_info_set_data (info, "sysmode", GUINT_TO_POINTER (sysmode), NULL);
+
+ /* Get HDR subsystem state */
+ hdrstate = g_byte_array_sized_new (25);
+ hdrstate->len = qcdm_cmd_hdr_subsys_state_info_new ((char *) hdrstate->data, 25, NULL);
+ g_assert (hdrstate->len);
+ mm_qcdm_serial_port_queue_command (port, hdrstate, 3, reg_hdrstate_cb, info);
+ } else {
+ /* No service */
+ set_callback_1x_state_helper (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
+ set_callback_evdo_state_helper (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
+ mm_callback_info_schedule (info);
+ }
+}
+
+static void
get_registration_state (MMModemCdma *modem,
MMModemCdmaRegistrationStateFn callback,
gpointer user_data)
@@ -1744,13 +1877,14 @@ get_registration_state (MMModemCdma *modem,
port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (modem), &info->error);
if (!port && !priv->qcdm) {
- g_message ("Returning saved registration states: 1x: %d EVDO: %d",
- priv->cdma_1x_reg_state, priv->evdo_reg_state);
+ mm_dbg ("Returning saved registration states: 1x: %d EVDO: %d",
+ priv->cdma_1x_reg_state, priv->evdo_reg_state);
mm_generic_cdma_query_reg_state_set_callback_1x_state (info, priv->cdma_1x_reg_state);
mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, priv->evdo_reg_state);
mm_callback_info_schedule (info);
return;
}
+ g_clear_error (&info->error);
/* Use QCDM for Call Manager state or HDR state before trying CAD, since
* CAD doesn't always reflect the state of the HDR radio's registration
@@ -2155,6 +2289,9 @@ get_property (GObject *object, guint prop_id,
case MM_MODEM_PROP_TYPE:
g_value_set_uint (value, MM_MODEM_TYPE_CDMA);
break;
+ case MM_MODEM_CDMA_PROP_MEID:
+ g_value_set_string (value, priv->meid);
+ break;
case PROP_EVDO_REV0:
g_value_set_boolean (value, priv->evdo_rev0);
break;
@@ -2207,6 +2344,10 @@ mm_generic_cdma_class_init (MMGenericCdmaClass *klass)
MM_MODEM_PROP_TYPE,
MM_MODEM_TYPE);
+ g_object_class_override_property (object_class,
+ MM_MODEM_CDMA_PROP_MEID,
+ MM_MODEM_CDMA_MEID);
+
g_object_class_install_property (object_class, PROP_EVDO_REV0,
g_param_spec_boolean (MM_GENERIC_CDMA_EVDO_REV0,
"EVDO rev0",
diff --git a/src/mm-generic-cdma.h b/src/mm-generic-cdma.h
index e4f9e57..350c58e 100644
--- a/src/mm-generic-cdma.h
+++ b/src/mm-generic-cdma.h
@@ -21,6 +21,7 @@
#include "mm-modem-base.h"
#include "mm-modem-cdma.h"
#include "mm-at-serial-port.h"
+#include "mm-qcdm-serial-port.h"
#include "mm-callback-info.h"
#define MM_TYPE_GENERIC_CDMA (mm_generic_cdma_get_type ())
@@ -87,7 +88,9 @@ MMModem *mm_generic_cdma_new (const char *device,
const char *driver,
const char *plugin,
gboolean evdo_rev0,
- gboolean evdo_revA);
+ gboolean evdo_revA,
+ guint vendor,
+ guint product);
/* Private, for subclasses */
@@ -103,6 +106,9 @@ MMAtSerialPort *mm_generic_cdma_get_at_port (MMGenericCdma *modem, MMPortType pt
MMAtSerialPort *mm_generic_cdma_get_best_at_port (MMGenericCdma *modem,
GError **error);
+MMQcdmSerialPort *mm_generic_cdma_get_best_qcdm_port (MMGenericCdma *modem,
+ GError **error);
+
void mm_generic_cdma_update_cdma1x_quality (MMGenericCdma *self, guint32 quality);
void mm_generic_cdma_update_evdo_quality (MMGenericCdma *self, guint32 quality);
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index 08cde10..98713b0 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -25,6 +25,7 @@
#include "mm-modem-gsm-card.h"
#include "mm-modem-gsm-network.h"
#include "mm-modem-gsm-sms.h"
+#include "mm-modem-gsm-ussd.h"
#include "mm-modem-simple.h"
#include "mm-errors.h"
#include "mm-callback-info.h"
@@ -32,21 +33,26 @@
#include "mm-qcdm-serial-port.h"
#include "mm-serial-parsers.h"
#include "mm-modem-helpers.h"
-#include "mm-options.h"
+#include "mm-log.h"
#include "mm-properties-changed-signal.h"
#include "mm-utils.h"
+#include "mm-modem-location.h"
static void modem_init (MMModem *modem_class);
static void modem_gsm_card_init (MMModemGsmCard *gsm_card_class);
static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class);
static void modem_gsm_sms_init (MMModemGsmSms *gsm_sms_class);
+static void modem_gsm_ussd_init (MMModemGsmUssd *gsm_ussd_class);
static void modem_simple_init (MMModemSimple *class);
+static void modem_location_init (MMModemLocation *class);
G_DEFINE_TYPE_EXTENDED (MMGenericGsm, mm_generic_gsm, MM_TYPE_MODEM_BASE, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_CARD, modem_gsm_card_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_NETWORK, modem_gsm_network_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_SMS, modem_gsm_sms_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_LOCATION, modem_location_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_USSD, modem_gsm_ussd_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simple_init))
#define MM_GENERIC_GSM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_GENERIC_GSM, MMGenericGsmPrivate))
@@ -60,6 +66,9 @@ typedef struct {
gboolean pin_checked;
guint32 pin_check_tries;
guint pin_check_timeout;
+ char *simid;
+ gboolean simid_checked;
+ guint32 simid_tries;
MMModemGsmAllowedMode allowed_mode;
@@ -87,8 +96,14 @@ typedef struct {
MMCallbackInfo *pending_reg_info;
gboolean manual_reg;
+ gboolean cmer_enabled;
+ guint roam_ind;
+ guint signal_ind;
+ guint service_ind;
+
guint signal_quality_id;
- time_t signal_quality_timestamp;
+ time_t signal_emit_timestamp;
+ time_t signal_update_timestamp;
guint32 signal_quality;
gint cid;
@@ -99,6 +114,13 @@ typedef struct {
MMAtSerialPort *secondary;
MMQcdmSerialPort *qcdm;
MMPort *data;
+
+ /* Location API */
+ guint32 loc_caps;
+ gboolean loc_enabled;
+ gboolean loc_signal;
+
+ MMModemGsmUssdState ussd_state;
} MMGenericGsmPrivate;
static void get_registration_status (MMAtSerialPort *port, MMCallbackInfo *info);
@@ -139,10 +161,18 @@ static void reg_info_updated (MMGenericGsm *self,
gboolean update_name,
const char *oper_name);
+static void update_lac_ci (MMGenericGsm *self, gulong lac, gulong ci, guint idx);
+
+static void ciev_received (MMAtSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data);
+
MMModem *
mm_generic_gsm_new (const char *device,
const char *driver,
- const char *plugin)
+ const char *plugin,
+ guint vendor,
+ guint product)
{
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
@@ -152,6 +182,8 @@ mm_generic_gsm_new (const char *device,
MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_HW_VID, vendor,
+ MM_MODEM_HW_PID, product,
NULL));
}
@@ -235,6 +267,10 @@ pin_check_done (MMAtSerialPort *port,
else if (response && strstr (response->str, "+CPIN: ")) {
const char *str = strstr (response->str, "+CPIN: ") + 7;
+ /* Some phones (Motorola EZX models) seem to quote the response */
+ if (str[0] == '"')
+ str++;
+
if (g_str_has_prefix (str, "READY")) {
mm_modem_base_set_unlock_required (MM_MODEM_BASE (info->modem), NULL);
if (MM_MODEM_GSM_CARD_GET_INTERFACE (info->modem)->get_unlock_retries)
@@ -306,12 +342,26 @@ get_imei_cb (MMModem *modem,
}
}
+static void
+get_info_cb (MMModem *modem,
+ const char *manufacturer,
+ const char *model,
+ const char *version,
+ GError *error,
+ gpointer user_data)
+{
+ /* Base class handles saving the info for us */
+ if (modem)
+ mm_serial_port_close (MM_SERIAL_PORT (MM_GENERIC_GSM_GET_PRIVATE (modem)->primary));
+}
+
/*****************************************************************************/
static MMModemGsmNetworkRegStatus
-gsm_reg_status (MMGenericGsm *self)
+gsm_reg_status (MMGenericGsm *self, guint32 *out_idx)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ guint32 idx = 1;
/* Some devices (Blackberries for example) will respond to +CGREG, but
* return ERROR for +CREG, probably because their firmware is just stupid.
@@ -320,23 +370,36 @@ gsm_reg_status (MMGenericGsm *self)
*/
if ( priv->reg_status[0] == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME
- || priv->reg_status[0] == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING)
- return priv->reg_status[0];
+ || priv->reg_status[0] == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
+ idx = 0;
+ goto out;
+ }
if ( priv->reg_status[1] == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME
- || priv->reg_status[1] == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING)
- return priv->reg_status[1];
+ || priv->reg_status[1] == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
+ idx = 1;
+ goto out;
+ }
- if (priv->reg_status[0] == MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING)
- return priv->reg_status[0];
+ if (priv->reg_status[0] == MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING) {
+ idx = 0;
+ goto out;
+ }
- if (priv->reg_status[1] == MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING)
- return priv->reg_status[1];
+ if (priv->reg_status[1] == MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING) {
+ idx = 1;
+ goto out;
+ }
- if (priv->reg_status[0] != MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN)
- return priv->reg_status[0];
+ if (priv->reg_status[0] != MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN) {
+ idx = 0;
+ goto out;
+ }
- return priv->reg_status[1];
+out:
+ if (out_idx)
+ *out_idx = idx;
+ return priv->reg_status[idx];
}
void
@@ -350,7 +413,7 @@ mm_generic_gsm_update_enabled_state (MMGenericGsm *self,
if (stay_connected && (mm_modem_get_state (MM_MODEM (self)) >= MM_MODEM_STATE_DISCONNECTING))
return;
- switch (gsm_reg_status (self)) {
+ switch (gsm_reg_status (self, NULL)) {
case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_REGISTERED, reason);
@@ -373,13 +436,211 @@ check_valid (MMGenericGsm *self)
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
gboolean new_valid = FALSE;
- if (priv->primary && priv->data && priv->pin_checked)
+ if (priv->primary && priv->data && priv->pin_checked && priv->simid_checked)
new_valid = TRUE;
mm_modem_base_set_valid (MM_MODEM_BASE (self), new_valid);
}
+static void
+get_iccid_done (MMModem *modem,
+ const char *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMGenericGsmPrivate *priv;
+ const char *p = response;
+ GChecksum *sum = NULL;
+
+ if (error || !response || !strlen (response))
+ goto done;
+
+ sum = g_checksum_new (G_CHECKSUM_SHA1);
+
+ /* Make sure it looks like an ICCID */
+ while (*p) {
+ if (!isdigit (*p)) {
+ g_warning ("%s: invalid ICCID format (not a digit)", __func__);
+ goto done;
+ }
+ g_checksum_update (sum, (const guchar *) p++, 1);
+ }
+
+ priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
+ g_free (priv->simid);
+ priv->simid = g_strdup (g_checksum_get_string (sum));
+
+ mm_dbg ("SIM ID source '%s'", response);
+ mm_dbg ("SIM ID '%s'", priv->simid);
+
+ g_object_notify (G_OBJECT (modem), MM_MODEM_GSM_CARD_SIM_IDENTIFIER);
+
+done:
+ if (sum)
+ g_checksum_free (sum);
+
+ if (modem) {
+ MM_GENERIC_GSM_GET_PRIVATE (modem)->simid_checked = TRUE;
+ check_valid (MM_GENERIC_GSM (modem));
+ }
+}
+
+#define ICCID_CMD "+CRSM=176,12258,0,0,10"
+
+static void
+real_get_iccid_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ const char *str;
+ int sw1, sw2;
+ gboolean success = FALSE;
+ char buf[21], swapped[21];
+
+ if (error) {
+ info->error = g_error_copy (error);
+ goto done;
+ }
+
+ memset (buf, 0, sizeof (buf));
+ str = mm_strip_tag (response->str, "+CRSM:");
+ if (sscanf (str, "%d,%d,\"%20c\"", &sw1, &sw2, (char *) &buf) == 3)
+ success = TRUE;
+ else {
+ /* May not include quotes... */
+ if (sscanf (str, "%d,%d,%20c", &sw1, &sw2, (char *) &buf) == 3)
+ success = TRUE;
+ }
+
+ if (!success) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Could not parse the CRSM response");
+ goto done;
+ }
+
+ if ((sw1 == 0x90 && sw2 == 0x00) || (sw1 == 0x91) || (sw1 == 0x92) || (sw1 == 0x9f)) {
+ gsize len = 0;
+ int f_pos = -1, i;
+
+ /* Make sure the buffer is only digits or 'F' */
+ for (len = 0; len < sizeof (buf) && buf[len]; len++) {
+ if (isdigit (buf[len]))
+ continue;
+ if (buf[len] == 'F' || buf[len] == 'f') {
+ buf[len] = 'F'; /* canonicalize the F */
+ f_pos = len;
+ continue;
+ }
+ if (buf[len] == '\"') {
+ buf[len] = 0;
+ break;
+ }
+
+ /* Invalid character */
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "CRSM ICCID response contained invalid character '%c'",
+ buf[len]);
+ goto done;
+ }
+
+ /* BCD encoded ICCIDs are 20 digits long */
+ if (len != 20) {
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Invalid +CRSM ICCID response size (was %zd, expected 20)",
+ len);
+ goto done;
+ }
+
+ /* Ensure if there's an 'F' that it's second-to-last */
+ if ((f_pos >= 0) && (f_pos != len - 2)) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Invalid +CRSM ICCID length (unexpected F)");
+ goto done;
+ }
+
+ /* Swap digits in the EFiccid response to get the actual ICCID, each
+ * group of 2 digits is reversed in the +CRSM response. i.e.:
+ *
+ * 21436587 -> 12345678
+ */
+ memset (swapped, 0, sizeof (swapped));
+ for (i = 0; i < 10; i++) {
+ swapped[i * 2] = buf[(i * 2) + 1];
+ swapped[(i * 2) + 1] = buf[i * 2];
+ }
+
+ /* Zero out the F for 19 digit ICCIDs */
+ if (swapped[len - 1] == 'F')
+ swapped[len - 1] = 0;
+
+ mm_callback_info_set_result (info, g_strdup (swapped), g_free);
+ } else {
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
+
+ if (priv->simid_tries++ < 2) {
+ /* Try one more time... Gobi 1K cards may reply to the first
+ * request with '+CRSM: 106,134,""' which is bogus because
+ * subsequent requests work fine.
+ */
+ mm_at_serial_port_queue_command (port, ICCID_CMD, 20, real_get_iccid_done, info);
+ return;
+ } else {
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "SIM failed to handle CRSM request (sw1 %d sw2 %d)",
+ sw1, sw2);
+ }
+ }
+
+done:
+ /* Balance open from real_get_sim_iccid() */
+ mm_serial_port_close (MM_SERIAL_PORT (port));
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+real_get_sim_iccid (MMGenericGsm *self,
+ MMModemStringFn callback,
+ gpointer callback_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
+ GError *error = NULL;
+
+ port = mm_generic_gsm_get_best_at_port (self, &error);
+ if (!port) {
+ callback (MM_MODEM (self), NULL, error, callback_data);
+ g_clear_error (&error);
+ return;
+ }
+
+ if (!mm_serial_port_open (MM_SERIAL_PORT (port), &error)) {
+ callback (MM_MODEM (self), NULL, error, callback_data);
+ g_clear_error (&error);
+ return;
+ }
+
+ info = mm_callback_info_string_new (MM_MODEM (self), callback, callback_data);
+
+ /* READ BINARY of EFiccid (ICC Identification) ETSI TS 102.221 section 13.2 */
+ mm_at_serial_port_queue_command (port, ICCID_CMD, 20, real_get_iccid_done, info);
+}
+
+static void
+initial_iccid_check (MMGenericGsm *self)
+{
+ g_assert (MM_GENERIC_GSM_GET_CLASS (self)->get_sim_iccid);
+ MM_GENERIC_GSM_GET_CLASS (self)->get_sim_iccid (self, get_iccid_done, NULL);
+}
+
static void initial_pin_check_done (MMModem *modem, GError *error, gpointer user_data);
static gboolean
@@ -415,9 +676,13 @@ initial_pin_check_done (MMModem *modem, GError *error, gpointer user_data)
g_source_remove (priv->pin_check_timeout);
priv->pin_check_timeout = g_timeout_add_seconds (2, pin_check_again, modem);
} else {
+ /* Try to get the SIM ICCID after we've checked PIN status and the SIM
+ * is ready.
+ */
+ initial_iccid_check (MM_GENERIC_GSM (modem));
+
priv->pin_checked = TRUE;
mm_serial_port_close (MM_SERIAL_PORT (priv->primary));
- check_valid (MM_GENERIC_GSM (modem));
}
}
@@ -476,6 +741,34 @@ initial_imei_check (MMGenericGsm *self)
}
}
+static void
+initial_info_check (MMGenericGsm *self)
+{
+ GError *error = NULL;
+ MMGenericGsmPrivate *priv;
+
+ g_return_if_fail (MM_IS_GENERIC_GSM (self));
+ priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+
+ g_return_if_fail (priv->primary != NULL);
+
+ if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) {
+ /* Make sure echoing is off */
+ mm_at_serial_port_queue_command (priv->primary, "E0", 3, NULL, NULL);
+ mm_modem_base_get_card_info (MM_MODEM_BASE (self),
+ priv->primary,
+ NULL,
+ get_info_cb,
+ NULL);
+ } else {
+ g_warning ("%s: failed to open serial port: (%d) %s",
+ __func__,
+ error ? error->code : -1,
+ error && error->message ? error->message : "(unknown)");
+ g_clear_error (&error);
+ }
+}
+
static gboolean
owns_port (MMModem *modem, const char *subsys, const char *name)
{
@@ -519,6 +812,10 @@ mm_generic_gsm_grab_port (MMGenericGsm *self,
}
mm_gsm_creg_regex_destroy (array);
+ regex = g_regex_new ("\\r\\n\\+CIEV: (\\d+),(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, ciev_received, self, NULL);
+ g_regex_unref (regex);
+
if (ptype == MM_PORT_TYPE_PRIMARY) {
priv->primary = MM_AT_SERIAL_PORT (port);
if (!priv->data) {
@@ -526,12 +823,17 @@ mm_generic_gsm_grab_port (MMGenericGsm *self,
g_object_notify (G_OBJECT (self), MM_MODEM_DATA_DEVICE);
}
- /* Get modem's initial lock/unlock state */
- initial_pin_check (self);
+ /* Get the modem's general info */
+ initial_info_check (self);
- /* Get modem's IMEI number */
+ /* Get modem's IMEI */
initial_imei_check (self);
+ /* Get modem's initial lock/unlock state; this also ensures the
+ * SIM is ready by waiting if necessary for the SIM to initalize.
+ */
+ initial_pin_check (self);
+
} else if (ptype == MM_PORT_TYPE_SECONDARY)
priv->secondary = MM_AT_SERIAL_PORT (port);
} else if (MM_IS_QCDM_SERIAL_PORT (port)) {
@@ -615,6 +917,18 @@ release_port (MMModem *modem, const char *subsys, const char *name)
}
static void
+add_loc_capability (MMGenericGsm *self, guint32 cap)
+{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ guint32 old_caps = priv->loc_caps;
+
+ priv->loc_caps |= cap;
+ if (priv->loc_caps != old_caps) {
+ g_object_notify (G_OBJECT (self), MM_MODEM_LOCATION_CAPABILITIES);
+ }
+}
+
+static void
reg_poll_response (MMAtSerialPort *port,
GString *response,
GError *error,
@@ -661,9 +975,12 @@ periodic_poll_cb (gpointer user_data)
if (priv->cgreg_poll)
mm_at_serial_port_queue_command (port, "+CGREG?", 10, reg_poll_response, self);
- mm_modem_gsm_network_get_signal_quality (MM_MODEM_GSM_NETWORK (self),
- periodic_signal_quality_cb,
- NULL);
+ /* Don't poll signal quality if we got a notification in the past 10 seconds */
+ if (time (NULL) - priv->signal_update_timestamp > 10) {
+ mm_modem_gsm_network_get_signal_quality (MM_MODEM_GSM_NETWORK (self),
+ periodic_signal_quality_cb,
+ NULL);
+ }
if (MM_GENERIC_GSM_GET_CLASS (self)->get_access_technology)
MM_GENERIC_GSM_GET_CLASS (self)->get_access_technology (self, periodic_access_tech_cb, NULL);
@@ -671,6 +988,57 @@ periodic_poll_cb (gpointer user_data)
return TRUE; /* continue running */
}
+#define CREG_NUM_TAG "creg-num"
+#define CGREG_NUM_TAG "cgreg-num"
+
+static void
+initial_unsolicited_reg_check_done (MMCallbackInfo *info)
+{
+ MMGenericGsmPrivate *priv;
+ guint creg_num, cgreg_num;
+
+ if (!info->modem || info->error)
+ goto done;
+
+ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
+ if (!priv->secondary)
+ goto done;
+
+ /* Enable unsolicited registration responses on secondary ports too,
+ * to ensure that we get the response even if the modem is connected
+ * on the primary port. We enable responses on both ports because we
+ * cannot trust modems to reliably send the responses on the port we
+ * enable them on.
+ */
+
+ creg_num = GPOINTER_TO_UINT (mm_callback_info_get_data (info, CREG_NUM_TAG));
+ switch (creg_num) {
+ case 1:
+ mm_at_serial_port_queue_command (priv->secondary, "+CREG=1", 3, NULL, NULL);
+ break;
+ case 2:
+ mm_at_serial_port_queue_command (priv->secondary, "+CREG=2", 3, NULL, NULL);
+ break;
+ default:
+ break;
+ }
+
+ cgreg_num = GPOINTER_TO_UINT (mm_callback_info_get_data (info, CGREG_NUM_TAG));
+ switch (cgreg_num) {
+ case 1:
+ mm_at_serial_port_queue_command (priv->secondary, "+CGREG=1", 3, NULL, NULL);
+ break;
+ case 2:
+ mm_at_serial_port_queue_command (priv->secondary, "+CGREG=2", 3, NULL, NULL);
+ break;
+ default:
+ break;
+ }
+
+done:
+ mm_callback_info_schedule (info);
+}
+
static void
cgreg1_done (MMAtSerialPort *port,
GString *response,
@@ -688,11 +1056,14 @@ cgreg1_done (MMAtSerialPort *port,
/* The modem doesn't like unsolicited CGREG, so we'll need to poll */
priv->cgreg_poll = TRUE;
- }
+ } else
+ mm_callback_info_set_data (info, CGREG_NUM_TAG, GUINT_TO_POINTER (1), NULL);
+
/* Success; get initial state */
mm_at_serial_port_queue_command (port, "+CGREG?", 10, reg_poll_response, info->modem);
}
- mm_callback_info_schedule (info);
+
+ initial_unsolicited_reg_check_done (info);
}
static void
@@ -711,11 +1082,15 @@ cgreg2_done (MMAtSerialPort *port,
/* Try CGREG=1 instead */
mm_at_serial_port_queue_command (port, "+CGREG=1", 3, cgreg1_done, info);
} else {
+ add_loc_capability (MM_GENERIC_GSM (info->modem), MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI);
+
+ mm_callback_info_set_data (info, CGREG_NUM_TAG, GUINT_TO_POINTER (2), NULL);
+
/* Success; get initial state */
mm_at_serial_port_queue_command (port, "+CGREG?", 10, reg_poll_response, info->modem);
/* All done */
- mm_callback_info_schedule (info);
+ initial_unsolicited_reg_check_done (info);
}
} else {
/* Modem got removed */
@@ -740,7 +1115,9 @@ creg1_done (MMAtSerialPort *port,
/* The modem doesn't like unsolicited CREG, so we'll need to poll */
priv->creg_poll = TRUE;
- }
+ } else
+ mm_callback_info_set_data (info, CREG_NUM_TAG, GUINT_TO_POINTER (1), NULL);
+
/* Success; get initial state */
mm_at_serial_port_queue_command (port, "+CREG?", 10, reg_poll_response, info->modem);
@@ -767,6 +1144,10 @@ creg2_done (MMAtSerialPort *port,
g_clear_error (&info->error);
mm_at_serial_port_queue_command (port, "+CREG=1", 3, creg1_done, info);
} else {
+ add_loc_capability (MM_GENERIC_GSM (info->modem), MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI);
+
+ mm_callback_info_set_data (info, CREG_NUM_TAG, GUINT_TO_POINTER (2), NULL);
+
/* Success; get initial state */
mm_at_serial_port_queue_command (port, "+CREG?", 10, reg_poll_response, info->modem);
@@ -807,6 +1188,7 @@ static guint32 best_charsets[] = {
MM_MODEM_CHARSET_UCS2,
MM_MODEM_CHARSET_8859_1,
MM_MODEM_CHARSET_IRA,
+ MM_MODEM_CHARSET_GSM,
MM_MODEM_CHARSET_UNKNOWN
};
@@ -865,7 +1247,7 @@ supported_charsets_done (MMModem *modem,
}
/* Switch the device's charset; we prefer UTF-8, but UCS2 will do too */
- mm_modem_set_charset (modem, MM_MODEM_CHARSET_UTF8, enabled_set_charset_done, info);
+ mm_modem_set_charset (modem, best_charsets[0], enabled_set_charset_done, info);
}
static void
@@ -881,14 +1263,87 @@ get_allowed_mode_done (MMModem *modem,
}
static void
-get_enable_info_done (MMModem *modem,
- const char *manufacturer,
- const char *model,
- const char *version,
- GError *error,
- gpointer user_data)
+ciev_received (MMAtSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data)
+{
+ MMGenericGsm *self = MM_GENERIC_GSM (user_data);
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ int quality = 0, ind = 0;
+ char *str;
+
+ if (!priv->cmer_enabled)
+ return;
+
+ str = g_match_info_fetch (info, 1);
+ if (str)
+ ind = atoi (str);
+ g_free (str);
+
+ if (ind == priv->signal_ind) {
+ str = g_match_info_fetch (info, 2);
+ if (str) {
+ quality = atoi (str);
+ mm_generic_gsm_update_signal_quality (self, quality * 20);
+ }
+ g_free (str);
+ }
+
+ /* FIXME: handle roaming and service indicators */
+}
+
+static void
+cmer_cb (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
- /* Modem base class handles the response for us */
+ if (!error) {
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (user_data);
+
+ priv->cmer_enabled = TRUE;
+
+ /* Enable CMER on the secondary port if we can too */
+ if (priv->secondary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary)))
+ mm_at_serial_port_queue_command (priv->secondary, "+CMER=3,0,0,1", 3, NULL, NULL);
+ }
+}
+
+static void
+cind_cb (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMGenericGsm *self;
+ MMGenericGsmPrivate *priv;
+ GHashTable *indicators;
+
+ if (error)
+ return;
+
+ self = MM_GENERIC_GSM (user_data);
+ priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+
+ indicators = mm_parse_cind_test_response (response->str, NULL);
+ if (indicators) {
+ CindResponse *r;
+
+ r = g_hash_table_lookup (indicators, "signal");
+ if (r)
+ priv->signal_ind = cind_response_get_index (r);
+
+ r = g_hash_table_lookup (indicators, "roam");
+ if (r)
+ priv->roam_ind = cind_response_get_index (r);
+
+ r = g_hash_table_lookup (indicators, "service");
+ if (r)
+ priv->service_ind = cind_response_get_index (r);
+
+ mm_at_serial_port_queue_command (port, "+CMER=3,0,0,1", 3, cmer_cb, self);
+ g_hash_table_destroy (indicators);
+ }
}
void
@@ -916,20 +1371,20 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self,
*/
if (priv->secondary) {
if (!mm_serial_port_open (MM_SERIAL_PORT (priv->secondary), &error)) {
- if (mm_options_debug ()) {
- g_warning ("%s: error opening secondary port: (%d) %s",
- __func__,
- error ? error->code : -1,
- error && error->message ? error->message : "(unknown)");
- }
+ mm_dbg ("error opening secondary port: (%d) %s",
+ error ? error->code : -1,
+ error && error->message ? error->message : "(unknown)");
}
}
/* Try to enable XON/XOFF flow control */
mm_at_serial_port_queue_command (priv->primary, "+IFC=1,1", 3, NULL, NULL);
- /* Grab device info right away */
- mm_modem_get_info (MM_MODEM (self), get_enable_info_done, NULL);
+ mm_at_serial_port_queue_command (priv->primary, "+CIND=?", 3, cind_cb, self);
+
+ /* Try one more time to get the SIM ID */
+ if (!priv->simid)
+ MM_GENERIC_GSM_GET_CLASS (self)->get_sim_iccid (self, get_iccid_done, NULL);
/* Get allowed mode */
if (MM_GENERIC_GSM_GET_CLASS (self)->get_allowed_mode)
@@ -1109,6 +1564,7 @@ disable_flash_done (MMSerialPort *port,
GError *error,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv;
MMCallbackInfo *info = user_data;
MMModemState prev_state;
char *cmd = NULL;
@@ -1127,9 +1583,21 @@ disable_flash_done (MMSerialPort *port,
return;
}
+ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
+
/* Disable unsolicited messages */
- mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "AT+CREG=0", 3, NULL, NULL);
- mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "AT+CGREG=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "+CREG=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "+CGREG=0", 3, NULL, NULL);
+
+ if (priv->cmer_enabled) {
+ mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "+CMER=0", 3, NULL, NULL);
+
+ /* And on the secondary port */
+ if (priv->secondary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary)))
+ mm_at_serial_port_queue_command (priv->secondary, "+CMER=0", 3, NULL, NULL);
+
+ priv->cmer_enabled = FALSE;
+ }
g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_POWER_DOWN_CMD, &cmd, NULL);
if (cmd && strlen (cmd))
@@ -1140,6 +1608,15 @@ disable_flash_done (MMSerialPort *port,
}
static void
+secondary_unsolicited_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ mm_serial_port_close_force (MM_SERIAL_PORT (port));
+}
+
+static void
disable (MMModem *modem,
MMModemFn callback,
gpointer user_data)
@@ -1170,15 +1647,16 @@ disable (MMModem *modem,
priv->pin_check_timeout = 0;
}
- priv->lac[0] = 0;
- priv->lac[1] = 0;
- priv->cell_id[0] = 0;
- priv->cell_id[1] = 0;
+ update_lac_ci (self, 0, 0, 0);
+ update_lac_ci (self, 0, 0, 1);
_internal_update_access_technology (self, MM_MODEM_GSM_ACCESS_TECH_UNKNOWN);
- /* Close the secondary port if its open */
- if (priv->secondary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary)))
- mm_serial_port_close_force (MM_SERIAL_PORT (priv->secondary));
+ /* Clean up the secondary port if it's open */
+ if (priv->secondary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary))) {
+ mm_at_serial_port_queue_command (priv->secondary, "+CREG=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (priv->secondary, "+CGREG=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (priv->secondary, "+CMER=0", 3, secondary_unsolicited_done, NULL);
+ }
info = mm_callback_info_new (modem, callback, user_data);
@@ -1370,6 +1848,7 @@ get_card_info (MMModem *modem,
}
#define PIN_PORT_TAG "pin-port"
+#define SAVED_ERROR_TAG "error"
static void
pin_puk_recheck_done (MMModem *modem, GError *error, gpointer user_data);
@@ -1389,6 +1868,7 @@ pin_puk_recheck_done (MMModem *modem, GError *error, gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMSerialPort *port;
+ GError *saved_error;
/* Clear the pin check timeout to ensure that it won't ever get a
* stale MMCallbackInfo if the modem got removed. We'll reschedule it here
@@ -1429,6 +1909,13 @@ pin_puk_recheck_done (MMModem *modem, GError *error, gpointer user_data)
if (modem && port)
mm_serial_port_close (port);
+ /* If we have a saved error from sending PIN/PUK, return that to callers */
+ saved_error = mm_callback_info_get_data (info, SAVED_ERROR_TAG);
+ if (saved_error) {
+ g_clear_error (&info->error);
+ info->error = saved_error;
+ }
+
mm_callback_info_schedule (info);
}
@@ -1441,10 +1928,18 @@ send_puk_done (MMAtSerialPort *port,
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
if (error) {
- info->error = g_error_copy (error);
- mm_callback_info_schedule (info);
- mm_serial_port_close (MM_SERIAL_PORT (port));
- return;
+ if (error->domain != MM_MOBILE_ERROR) {
+ info->error = g_error_copy (error);
+ mm_callback_info_schedule (info);
+ mm_serial_port_close (MM_SERIAL_PORT (port));
+ return;
+ } else {
+ /* Keep the real error around so we can send it back
+ * when we're done rechecking CPIN status.
+ */
+ mm_callback_info_set_data (info, SAVED_ERROR_TAG,
+ g_error_copy (error), NULL);
+ }
}
/* Get latest PIN status */
@@ -1496,10 +1991,18 @@ send_pin_done (MMAtSerialPort *port,
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
if (error) {
- info->error = g_error_copy (error);
- mm_callback_info_schedule (info);
- mm_serial_port_close (MM_SERIAL_PORT (port));
- return;
+ if (error->domain != MM_MOBILE_ERROR) {
+ info->error = g_error_copy (error);
+ mm_callback_info_schedule (info);
+ mm_serial_port_close (MM_SERIAL_PORT (port));
+ return;
+ } else {
+ /* Keep the real error around so we can send it back
+ * when we're done rechecking CPIN status.
+ */
+ mm_callback_info_set_data (info, SAVED_ERROR_TAG,
+ g_error_copy (error), NULL);
+ }
}
/* Get latest PIN status */
@@ -1634,9 +2137,9 @@ reg_info_updated (MMGenericGsm *self,
g_return_if_fail ( rs_type == MM_GENERIC_GSM_REG_TYPE_CS
|| rs_type == MM_GENERIC_GSM_REG_TYPE_PS);
- old_status = gsm_reg_status (self);
+ old_status = gsm_reg_status (self, NULL);
priv->reg_status[rs_type - 1] = status;
- if (gsm_reg_status (self) != old_status)
+ if (gsm_reg_status (self, NULL) != old_status)
changed = TRUE;
}
@@ -1658,7 +2161,7 @@ reg_info_updated (MMGenericGsm *self,
if (changed) {
mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (self),
- gsm_reg_status (self),
+ gsm_reg_status (self, NULL),
priv->oper_code,
priv->oper_name);
}
@@ -1716,12 +2219,22 @@ parse_operator (const char *reply, MMModemCharset cur_charset)
g_regex_unref (r);
}
- /* Some modems (Option & HSO) return the operator name as a hexadecimal
- * string of the bytes of the operator name as encoded by the current
- * character set.
- */
- if (operator && (cur_charset == MM_MODEM_CHARSET_UCS2))
- convert_operator_from_ucs2 (&operator);
+ if (operator) {
+ /* Some modems (Option & HSO) return the operator name as a hexadecimal
+ * string of the bytes of the operator name as encoded by the current
+ * character set.
+ */
+ if (cur_charset == MM_MODEM_CHARSET_UCS2)
+ convert_operator_from_ucs2 (&operator);
+
+ /* Ensure the operator name is valid UTF-8 so that we can send it
+ * through D-Bus and such.
+ */
+ if (!g_utf8_validate (operator, -1, NULL)) {
+ g_free (operator);
+ operator = NULL;
+ }
+ }
return operator;
}
@@ -1803,7 +2316,7 @@ roam_disconnect_done (MMModem *modem,
GError *error,
gpointer user_data)
{
- g_message ("Disconnected because roaming is not allowed");
+ mm_info ("Disconnected because roaming is not allowed");
}
static void
@@ -1834,9 +2347,9 @@ mm_generic_gsm_set_reg_status (MMGenericGsm *self,
if (priv->reg_status[rs_type - 1] == status)
return;
- g_debug ("%s registration state changed: %d",
- (rs_type == MM_GENERIC_GSM_REG_TYPE_CS) ? "CS" : "PS",
- status);
+ mm_dbg ("%s registration state changed: %d",
+ (rs_type == MM_GENERIC_GSM_REG_TYPE_CS) ? "CS" : "PS",
+ status);
priv->reg_status[rs_type - 1] = status;
port = mm_generic_gsm_get_best_at_port (self, NULL);
@@ -1948,18 +2461,15 @@ reg_state_changed (MMAtSerialPort *port,
{
MMGenericGsm *self = MM_GENERIC_GSM (user_data);
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
- guint32 state = 0, idx;
+ guint32 state = 0;
gulong lac = 0, cell_id = 0;
gint act = -1;
gboolean cgreg = FALSE;
GError *error = NULL;
if (!mm_gsm_parse_creg_response (match_info, &state, &lac, &cell_id, &act, &cgreg, &error)) {
- if (mm_options_debug ()) {
- g_warning ("%s: error parsing unsolicited registration: %s",
- __func__,
- error && error->message ? error->message : "(unknown)");
- }
+ mm_warn ("error parsing unsolicited registration: %s",
+ error && error->message ? error->message : "(unknown)");
return;
}
@@ -1974,9 +2484,7 @@ reg_state_changed (MMAtSerialPort *port,
}
}
- idx = cgreg ? 1 : 0;
- priv->lac[idx] = lac;
- priv->cell_id[idx] = cell_id;
+ update_lac_ci (self, lac, cell_id, cgreg ? 1 : 0);
/* Only update access technology if it appeared in the CREG/CGREG response */
if (act != -1)
@@ -2014,7 +2522,7 @@ handle_reg_status_response (MMGenericGsm *self,
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
GMatchInfo *match_info;
- guint32 status = 0, idx;
+ guint32 status = 0;
gulong lac = 0, ci = 0;
gint act = -1;
gboolean cgreg = FALSE;
@@ -2043,9 +2551,7 @@ handle_reg_status_response (MMGenericGsm *self,
}
/* Success; update cached location information */
- idx = cgreg ? 1 : 0;
- priv->lac[idx] = lac;
- priv->cell_id[idx] = ci;
+ update_lac_ci (self, lac, ci, cgreg ? 1 : 0);
/* Only update access technology if it appeared in the CREG/CGREG response */
if (act != -1)
@@ -2108,7 +2614,7 @@ get_reg_status_done (MMAtSerialPort *port,
goto reg_done;
}
- status = gsm_reg_status (self);
+ status = gsm_reg_status (self, NULL);
if ( status != MM_MODEM_GSM_NETWORK_REG_STATUS_HOME
&& status != MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING
&& status != MM_MODEM_GSM_NETWORK_REG_STATUS_DENIED) {
@@ -2222,7 +2728,7 @@ do_register (MMModemGsmNetwork *modem,
if (network_id) {
command = g_strdup_printf ("+COPS=1,2,\"%s\"", network_id);
priv->manual_reg = TRUE;
- } else if (reg_is_idle (gsm_reg_status (self)) || priv->manual_reg) {
+ } else if (reg_is_idle (gsm_reg_status (self, NULL)) || priv->manual_reg) {
command = g_strdup ("+COPS=0,,");
priv->manual_reg = FALSE;
}
@@ -2260,7 +2766,7 @@ gsm_network_reg_info_invoke (MMCallbackInfo *info)
MMModemGsmNetworkRegInfoFn callback = (MMModemGsmNetworkRegInfoFn) info->callback;
callback (MM_MODEM_GSM_NETWORK (info->modem),
- gsm_reg_status (MM_GENERIC_GSM (info->modem)),
+ gsm_reg_status (MM_GENERIC_GSM (info->modem), NULL),
priv->oper_code,
priv->oper_name,
info->error,
@@ -2369,7 +2875,7 @@ connect (MMModem *modem,
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
MMCallbackInfo *info;
char *command;
- guint32 cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (modem));
+ gint cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (modem));
info = mm_callback_info_new (modem, callback, user_data);
@@ -2803,7 +3309,7 @@ emit_signal_quality_change (gpointer user_data)
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
priv->signal_quality_id = 0;
- priv->signal_quality_timestamp = time (NULL);
+ priv->signal_emit_timestamp = time (NULL);
mm_modem_gsm_network_signal_quality (MM_MODEM_GSM_NETWORK (self), priv->signal_quality);
return FALSE;
}
@@ -2820,6 +3326,8 @@ mm_generic_gsm_update_signal_quality (MMGenericGsm *self, guint32 quality)
priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ priv->signal_update_timestamp = time (NULL);
+
if (priv->signal_quality == quality)
return;
@@ -2831,12 +3339,12 @@ mm_generic_gsm_update_signal_quality (MMGenericGsm *self, guint32 quality)
* haven't been any updates in a while.
*/
if (!priv->signal_quality_id) {
- if (priv->signal_quality_timestamp > 0) {
+ if (priv->signal_emit_timestamp > 0) {
time_t curtime;
long int diff;
curtime = time (NULL);
- diff = curtime - priv->signal_quality_timestamp;
+ diff = curtime - priv->signal_emit_timestamp;
if (diff == 0) {
/* If the device is sending more than one update per second,
* make sure we don't spam clients with signals.
@@ -2861,11 +3369,43 @@ mm_generic_gsm_update_signal_quality (MMGenericGsm *self, guint32 quality)
}
}
+#define CIND_TAG "+CIND:"
+
static void
-get_signal_quality_done (MMAtSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
+get_cind_signal_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMGenericGsmPrivate *priv;
+ GByteArray *indicators;
+ guint quality;
+
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (!info->error) {
+ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
+
+ indicators = mm_parse_cind_query_response (response->str, &info->error);
+ if (indicators) {
+ if (indicators->len >= priv->signal_ind) {
+ quality = g_array_index (indicators, guint8, priv->signal_ind);
+ quality = CLAMP (quality, 0, 5) * 20;
+ mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (info->modem), quality);
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (quality), NULL);
+ }
+ g_byte_array_free (indicators, TRUE);
+ }
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_csq_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
char *reply = response->str;
@@ -2918,9 +3458,13 @@ get_signal_quality (MMModemGsmNetwork *modem,
info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), NULL);
- if (port)
- mm_at_serial_port_queue_command (port, "+CSQ", 3, get_signal_quality_done, info);
- else {
+ if (port) {
+ /* Prefer +CIND if the modem supports it, fall back to +CSQ otherwise */
+ if (priv->signal_ind)
+ mm_at_serial_port_queue_command (port, "+CIND?", 3, get_cind_signal_done, info);
+ else
+ mm_at_serial_port_queue_command (port, "+CSQ", 3, get_csq_done, info);
+ } else {
/* Use cached signal quality */
mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->signal_quality), NULL);
mm_callback_info_schedule (info);
@@ -3282,7 +3826,7 @@ sms_send_done (MMAtSerialPort *port,
}
static void
-sms_send (MMModemGsmSms *modem,
+sms_send (MMModemGsmSms *modem,
const char *number,
const char *text,
const char *smsc,
@@ -3348,6 +3892,219 @@ mm_generic_gsm_get_best_at_port (MMGenericGsm *self, GError **error)
}
/*****************************************************************************/
+/* MMModemGsmUssd interface */
+
+static void
+ussd_update_state (MMGenericGsm *self, MMModemGsmUssdState new_state)
+{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+
+ if (new_state != priv->ussd_state) {
+ priv->ussd_state = new_state;
+ g_object_notify (G_OBJECT (self), MM_MODEM_GSM_USSD_STATE);
+ }
+}
+
+static void
+ussd_send_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMGenericGsmPrivate *priv;
+ gint status;
+ gboolean parsed = FALSE;
+ MMModemGsmUssdState ussd_state = MM_MODEM_GSM_USSD_STATE_IDLE;
+ const char *str, *start = NULL, *end = NULL;
+ char *reply = NULL, *converted;
+
+ if (error) {
+ info->error = g_error_copy (error);
+ goto done;
+ }
+
+ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
+ ussd_state = priv->ussd_state;
+
+ str = mm_strip_tag (response->str, "+CUSD:");
+ if (!str || !isdigit (*str))
+ goto done;
+
+ status = g_ascii_digit_value (*str);
+ switch (status) {
+ case 0: /* no further action required */
+ ussd_state = MM_MODEM_GSM_USSD_STATE_IDLE;
+ break;
+ case 1: /* further action required */
+ ussd_state = MM_MODEM_GSM_USSD_STATE_USER_RESPONSE;
+ break;
+ case 2:
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "USSD terminated by network.");
+ ussd_state = MM_MODEM_GSM_USSD_STATE_IDLE;
+ break;
+ case 4:
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Operiation not supported.");
+ ussd_state = MM_MODEM_GSM_USSD_STATE_IDLE;
+ break;
+ default:
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Unknown USSD reply %d", status);
+ ussd_state = MM_MODEM_GSM_USSD_STATE_IDLE;
+ break;
+ }
+ if (info->error)
+ goto done;
+
+ /* look for the reply */
+ if ((start = strchr (str, '"')) && (end = strrchr (str, '"')) && (start != end))
+ reply = g_strndup (start + 1, end - start -1);
+
+ if (reply) {
+ /* look for the reply data coding scheme */
+ if ((start = strrchr (end, ',')) != NULL)
+ mm_dbg ("USSD data coding scheme %d", atoi (start + 1));
+
+ converted = mm_modem_charset_hex_to_utf8 (reply, priv->cur_charset);
+ mm_callback_info_set_result (info, converted, g_free);
+ parsed = TRUE;
+ g_free (reply);
+ }
+
+done:
+ if (!parsed && !info->error) {
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Could not parse USSD reply '%s'",
+ response->str);
+ }
+ mm_callback_info_schedule (info);
+
+ if (info->modem)
+ ussd_update_state (MM_GENERIC_GSM (info->modem), ussd_state);
+}
+
+static void
+ussd_send (MMModemGsmUssd *modem,
+ const char *command,
+ MMModemStringFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ char *atc_command;
+ char *hex;
+ GByteArray *ussd_command = g_byte_array_new();
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
+ MMAtSerialPort *port;
+
+ info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ /* encode to cur_charset */
+ g_warn_if_fail (mm_modem_charset_byte_array_append (ussd_command, command, FALSE, priv->cur_charset));
+ /* convert to hex representation */
+ hex = utils_bin2hexstr (ussd_command->data, ussd_command->len);
+ g_byte_array_free (ussd_command, TRUE);
+ atc_command = g_strdup_printf ("+CUSD=1,\"%s\",15", hex);
+ g_free (hex);
+
+ mm_at_serial_port_queue_command (port, atc_command, 10, ussd_send_done, info);
+ g_free (atc_command);
+
+ ussd_update_state (MM_GENERIC_GSM (modem), MM_MODEM_GSM_USSD_STATE_ACTIVE);
+}
+
+static void
+ussd_initiate (MMModemGsmUssd *modem,
+ const char *command,
+ MMModemStringFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
+ info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
+
+ if (priv->ussd_state != MM_MODEM_GSM_USSD_STATE_IDLE) {
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "USSD session already active.");
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ ussd_send (modem, command, callback, user_data);
+ return;
+}
+
+static void
+ussd_respond (MMModemGsmUssd *modem,
+ const char *command,
+ MMModemStringFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
+ info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
+
+ if (priv->ussd_state != MM_MODEM_GSM_USSD_STATE_USER_RESPONSE) {
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "No active USSD session, cannot respond.");
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ ussd_send (modem, command, callback, user_data);
+ return;
+}
+
+static void
+ussd_cancel_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ if (error)
+ info->error = g_error_copy (error);
+
+ mm_callback_info_schedule (info);
+
+ if (info->modem)
+ ussd_update_state (MM_GENERIC_GSM (info->modem), MM_MODEM_GSM_USSD_STATE_IDLE);
+}
+
+static void
+ussd_cancel (MMModemGsmUssd *modem,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
+
+ info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (port, "+CUSD=2", 10, ussd_cancel_done, info);
+}
+
+/*****************************************************************************/
/* MMModemSimple interface */
typedef enum {
@@ -3481,6 +4238,7 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data)
gboolean done = FALSE;
MMModemGsmAllowedMode allowed_mode;
gboolean home_only = FALSE;
+ char *data_device;
info->error = mm_modem_check_removed (modem, error);
if (info->error)
@@ -3488,16 +4246,9 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data)
priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
- if (mm_options_debug ()) {
- GTimeVal tv;
- char *data_device;
-
- g_object_get (G_OBJECT (modem), MM_MODEM_DATA_DEVICE, &data_device, NULL);
- g_get_current_time (&tv);
- g_debug ("<%ld.%ld> (%s): simple connect state %d",
- tv.tv_sec, tv.tv_usec, data_device, state);
- g_free (data_device);
- }
+ g_object_get (G_OBJECT (modem), MM_MODEM_DATA_DEVICE, &data_device, NULL);
+ mm_dbg ("(%s): simple connect state %d", data_device, state);
+ g_free (data_device);
switch (state) {
case SIMPLE_STATE_CHECK_PIN:
@@ -3564,7 +4315,7 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data)
priv->roam_allowed = !home_only;
/* Don't connect if we're not supposed to be roaming */
- status = gsm_reg_status (MM_GENERIC_GSM (modem));
+ status = gsm_reg_status (MM_GENERIC_GSM (modem), NULL);
if (home_only && (status == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING)) {
info->error = g_error_new_literal (MM_MOBILE_ERROR,
MM_MOBILE_ERROR_GPRS_ROAMING_NOT_ALLOWED,
@@ -3596,29 +4347,21 @@ simple_connect (MMModemSimple *simple,
gpointer user_data)
{
MMCallbackInfo *info;
-
- /* If debugging, list all the simple connect properties */
- if (mm_options_debug ()) {
- GHashTableIter iter;
- gpointer key, value;
- GTimeVal tv;
- char *data_device;
-
- g_object_get (G_OBJECT (simple), MM_MODEM_DATA_DEVICE, &data_device, NULL);
- g_get_current_time (&tv);
-
- g_hash_table_iter_init (&iter, properties);
- while (g_hash_table_iter_next (&iter, &key, &value)) {
- char *val_str;
-
- val_str = g_strdup_value_contents ((GValue *) value);
- g_debug ("<%ld.%ld> (%s): %s => %s",
- tv.tv_sec, tv.tv_usec,
- data_device, (const char *) key, val_str);
- g_free (val_str);
- }
- g_free (data_device);
+ GHashTableIter iter;
+ gpointer key, value;
+ char *data_device;
+
+ /* List simple connect properties when debugging */
+ g_object_get (G_OBJECT (simple), MM_MODEM_DATA_DEVICE, &data_device, NULL);
+ g_hash_table_iter_init (&iter, properties);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ char *val_str;
+
+ val_str = g_strdup_value_contents ((GValue *) value);
+ mm_dbg ("(%s): %s => %s", data_device, (const char *) key, val_str);
+ g_free (val_str);
}
+ g_free (data_device);
info = mm_callback_info_new (MM_MODEM (simple), callback, user_data);
mm_callback_info_set_data (info, "simple-connect-properties",
@@ -3761,6 +4504,159 @@ simple_get_status (MMModemSimple *simple,
/*****************************************************************************/
+static gboolean
+gsm_lac_ci_available (MMGenericGsm *self, guint32 *out_idx)
+{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ MMModemGsmNetworkRegStatus status;
+ guint idx;
+
+ /* Must be registered, and have operator code, LAC and CI before GSM_LAC_CI is valid */
+ status = gsm_reg_status (self, &idx);
+ if (out_idx)
+ *out_idx = idx;
+
+ if ( status != MM_MODEM_GSM_NETWORK_REG_STATUS_HOME
+ && status != MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING)
+ return FALSE;
+
+ if (!priv->oper_code || !strlen (priv->oper_code))
+ return FALSE;
+
+ if (!priv->lac[idx] || !priv->cell_id[idx])
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+update_lac_ci (MMGenericGsm *self, gulong lac, gulong ci, guint idx)
+{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ gboolean changed = FALSE;
+
+ if (lac != priv->lac[idx]) {
+ priv->lac[idx] = lac;
+ changed = TRUE;
+ }
+
+ if (ci != priv->cell_id[idx]) {
+ priv->cell_id[idx] = ci;
+ changed = TRUE;
+ }
+
+ if (changed && gsm_lac_ci_available (self, NULL) && priv->loc_enabled && priv->loc_signal)
+ g_object_notify (G_OBJECT (self), MM_MODEM_LOCATION_LOCATION);
+}
+
+static void
+destroy_gvalue (gpointer data)
+{
+ GValue *value = (GValue *) data;
+
+ g_value_unset (value);
+ g_slice_free (GValue, value);
+}
+
+static GHashTable *
+make_location_hash (MMGenericGsm *self, GError **error)
+{
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ GHashTable *locations = NULL;
+ guint32 reg_idx = 0;
+ GValue *val;
+ char mcc[4] = { 0, 0, 0, 0 };
+ char mnc[4] = { 0, 0, 0, 0 };
+
+ if (priv->loc_caps == MM_MODEM_LOCATION_CAPABILITY_UNKNOWN) {
+ g_set_error_literal (error,
+ MM_MODEM_ERROR,
+ MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED,
+ "Modem has no location capabilities");
+ return NULL;
+ }
+
+ locations = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, destroy_gvalue);
+
+ if (!gsm_lac_ci_available (self, &reg_idx))
+ return locations;
+
+ memcpy (mcc, priv->oper_code, 3);
+ /* Not all modems report 6-digit MNCs */
+ memcpy (mnc, priv->oper_code + 3, 2);
+ if (strlen (priv->oper_code) == 6)
+ mnc[2] = priv->oper_code[5];
+
+ val = g_slice_new0 (GValue);
+ g_value_init (val, G_TYPE_STRING);
+ g_value_take_string (val, g_strdup_printf ("%s,%s,%lX,%lX",
+ mcc,
+ mnc,
+ priv->lac[reg_idx],
+ priv->cell_id[reg_idx]));
+ g_hash_table_insert (locations,
+ GUINT_TO_POINTER (MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI),
+ val);
+
+ return locations;
+}
+
+static void
+location_enable (MMModemLocation *modem,
+ gboolean loc_enable,
+ gboolean signal_location,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMGenericGsm *self = MM_GENERIC_GSM (modem);
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ MMCallbackInfo *info;
+
+ if (loc_enable != priv->loc_enabled) {
+ priv->loc_enabled = loc_enable;
+ g_object_notify (G_OBJECT (modem), MM_MODEM_LOCATION_ENABLED);
+ }
+
+ if (signal_location != priv->loc_signal) {
+ priv->loc_signal = signal_location;
+ g_object_notify (G_OBJECT (modem), MM_MODEM_LOCATION_SIGNALS_LOCATION);
+ }
+
+ if (loc_enable && signal_location && gsm_lac_ci_available (self, NULL))
+ g_object_notify (G_OBJECT (modem), MM_MODEM_LOCATION_LOCATION);
+
+ info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
+ mm_callback_info_schedule (info);
+}
+
+static void
+location_get (MMModemLocation *modem,
+ MMModemLocationGetFn callback,
+ gpointer user_data)
+{
+ MMGenericGsm *self = MM_GENERIC_GSM (modem);
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ GHashTable *locations = NULL;
+ GError *error = NULL;
+
+ if (priv->loc_caps == MM_MODEM_LOCATION_CAPABILITY_UNKNOWN) {
+ error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED,
+ "Modem has no location capabilities");
+ } else if (priv->loc_enabled)
+ locations = make_location_hash (self, &error);
+ else
+ locations = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ callback (modem, locations, error, user_data);
+ if (locations)
+ g_hash_table_destroy (locations);
+ g_clear_error (&error);
+}
+
+/*****************************************************************************/
+
static void
modem_state_changed (MMGenericGsm *self, GParamSpec *pspec, gpointer user_data)
{
@@ -3798,6 +4694,13 @@ modem_init (MMModem *modem_class)
}
static void
+modem_location_init (MMModemLocation *class)
+{
+ class->enable = location_enable;
+ class->get_location = location_get;
+}
+
+static void
modem_gsm_card_init (MMModemGsmCard *class)
{
class->get_imei = get_imei;
@@ -3828,6 +4731,14 @@ modem_gsm_sms_init (MMModemGsmSms *class)
}
static void
+modem_gsm_ussd_init (MMModemGsmUssd *class)
+{
+ class->initiate = ussd_initiate;
+ class->respond = ussd_respond;
+ class->cancel = ussd_cancel;
+}
+
+static void
modem_simple_init (MMModemSimple *class)
{
class->connect = simple_connect;
@@ -3845,12 +4756,49 @@ mm_generic_gsm_init (MMGenericGsm *self)
mm_properties_changed_signal_register_property (G_OBJECT (self),
MM_MODEM_GSM_NETWORK_ALLOWED_MODE,
+ NULL,
MM_MODEM_GSM_NETWORK_DBUS_INTERFACE);
mm_properties_changed_signal_register_property (G_OBJECT (self),
MM_MODEM_GSM_NETWORK_ACCESS_TECHNOLOGY,
+ NULL,
MM_MODEM_GSM_NETWORK_DBUS_INTERFACE);
+ mm_properties_changed_signal_register_property (G_OBJECT (self),
+ MM_MODEM_LOCATION_CAPABILITIES,
+ "Capabilities",
+ MM_MODEM_LOCATION_DBUS_INTERFACE);
+
+ mm_properties_changed_signal_register_property (G_OBJECT (self),
+ MM_MODEM_LOCATION_ENABLED,
+ "Enabled",
+ MM_MODEM_LOCATION_DBUS_INTERFACE);
+
+ mm_properties_changed_signal_register_property (G_OBJECT (self),
+ MM_MODEM_LOCATION_SIGNALS_LOCATION,
+ NULL,
+ MM_MODEM_LOCATION_DBUS_INTERFACE);
+
+ mm_properties_changed_signal_register_property (G_OBJECT (self),
+ MM_MODEM_LOCATION_LOCATION,
+ NULL,
+ MM_MODEM_LOCATION_DBUS_INTERFACE);
+
+ mm_properties_changed_signal_register_property (G_OBJECT (self),
+ MM_MODEM_GSM_USSD_STATE,
+ "State",
+ MM_MODEM_GSM_USSD_DBUS_INTERFACE);
+
+ mm_properties_changed_signal_register_property (G_OBJECT (self),
+ MM_MODEM_GSM_USSD_NETWORK_NOTIFICATION,
+ "NetworkNotification",
+ MM_MODEM_GSM_USSD_DBUS_INTERFACE);
+
+ mm_properties_changed_signal_register_property (G_OBJECT (self),
+ MM_MODEM_GSM_USSD_NETWORK_REQUEST,
+ "NetworkRequest",
+ MM_MODEM_GSM_USSD_DBUS_INTERFACE);
+
g_signal_connect (self, "notify::" MM_MODEM_STATE,
G_CALLBACK (modem_state_changed), NULL);
}
@@ -3869,6 +4817,14 @@ set_property (GObject *object, guint prop_id,
case MM_GENERIC_GSM_PROP_SUPPORTED_MODES:
case MM_GENERIC_GSM_PROP_ALLOWED_MODE:
case MM_GENERIC_GSM_PROP_ACCESS_TECHNOLOGY:
+ case MM_GENERIC_GSM_PROP_SIM_IDENTIFIER:
+ case MM_GENERIC_GSM_PROP_LOC_CAPABILITIES:
+ case MM_GENERIC_GSM_PROP_LOC_ENABLED:
+ case MM_GENERIC_GSM_PROP_LOC_SIGNAL:
+ case MM_GENERIC_GSM_PROP_LOC_LOCATION:
+ case MM_GENERIC_GSM_PROP_USSD_STATE:
+ case MM_GENERIC_GSM_PROP_USSD_NETWORK_REQUEST:
+ case MM_GENERIC_GSM_PROP_USSD_NETWORK_NOTIFICATION:
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -3876,11 +4832,30 @@ set_property (GObject *object, guint prop_id,
}
}
+static const char *
+ussd_state_to_string (MMModemGsmUssdState ussd_state)
+{
+ switch (ussd_state) {
+ case MM_MODEM_GSM_USSD_STATE_IDLE:
+ return "idle";
+ case MM_MODEM_GSM_USSD_STATE_ACTIVE:
+ return "active";
+ case MM_MODEM_GSM_USSD_STATE_USER_RESPONSE:
+ return "user-response";
+ default:
+ break;
+ }
+
+ g_warning ("Unknown GSM USSD state %d", ussd_state);
+ return "unknown";
+}
+
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (object);
+ GHashTable *locations = NULL;
switch (prop_id) {
case MM_MODEM_PROP_DATA_DEVICE:
@@ -3926,6 +4901,37 @@ get_property (GObject *object, guint prop_id,
else
g_value_set_uint (value, MM_MODEM_GSM_ACCESS_TECH_UNKNOWN);
break;
+ case MM_GENERIC_GSM_PROP_SIM_IDENTIFIER:
+ g_value_set_string (value, priv->simid);
+ break;
+ case MM_GENERIC_GSM_PROP_LOC_CAPABILITIES:
+ g_value_set_uint (value, priv->loc_caps);
+ break;
+ case MM_GENERIC_GSM_PROP_LOC_ENABLED:
+ g_value_set_boolean (value, priv->loc_enabled);
+ break;
+ case MM_GENERIC_GSM_PROP_LOC_SIGNAL:
+ g_value_set_boolean (value, priv->loc_signal);
+ break;
+ case MM_GENERIC_GSM_PROP_LOC_LOCATION:
+ /* We don't allow property accesses unless location change signalling
+ * is enabled, for security reasons.
+ */
+ if (priv->loc_enabled && priv->loc_signal)
+ locations = make_location_hash (MM_GENERIC_GSM (object), NULL);
+ else
+ locations = g_hash_table_new (g_direct_hash, g_direct_equal);
+ g_value_take_boxed (value, locations);
+ break;
+ case MM_GENERIC_GSM_PROP_USSD_STATE:
+ g_value_set_string (value, ussd_state_to_string (priv->ussd_state));
+ break;
+ case MM_GENERIC_GSM_PROP_USSD_NETWORK_REQUEST:
+ g_value_set_string (value, "");
+ break;
+ case MM_GENERIC_GSM_PROP_USSD_NETWORK_NOTIFICATION:
+ g_value_set_string (value, "");
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -3958,6 +4964,7 @@ finalize (GObject *object)
g_free (priv->oper_code);
g_free (priv->oper_name);
+ g_free (priv->simid);
G_OBJECT_CLASS (mm_generic_gsm_parent_class)->finalize (object);
}
@@ -3978,6 +4985,7 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass)
klass->do_enable = real_do_enable;
klass->do_enable_power_up_done = real_do_enable_power_up_done;
klass->do_disconnect = real_do_disconnect;
+ klass->get_sim_iccid = real_get_sim_iccid;
/* Properties */
g_object_class_override_property (object_class,
@@ -4004,6 +5012,38 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass)
MM_GENERIC_GSM_PROP_ACCESS_TECHNOLOGY,
MM_MODEM_GSM_NETWORK_ACCESS_TECHNOLOGY);
+ g_object_class_override_property (object_class,
+ MM_GENERIC_GSM_PROP_SIM_IDENTIFIER,
+ MM_MODEM_GSM_CARD_SIM_IDENTIFIER);
+
+ g_object_class_override_property (object_class,
+ MM_GENERIC_GSM_PROP_LOC_CAPABILITIES,
+ MM_MODEM_LOCATION_CAPABILITIES);
+
+ g_object_class_override_property (object_class,
+ MM_GENERIC_GSM_PROP_LOC_ENABLED,
+ MM_MODEM_LOCATION_ENABLED);
+
+ g_object_class_override_property (object_class,
+ MM_GENERIC_GSM_PROP_LOC_SIGNAL,
+ MM_MODEM_LOCATION_SIGNALS_LOCATION);
+
+ g_object_class_override_property (object_class,
+ MM_GENERIC_GSM_PROP_LOC_LOCATION,
+ MM_MODEM_LOCATION_LOCATION);
+
+ g_object_class_override_property (object_class,
+ MM_GENERIC_GSM_PROP_USSD_STATE,
+ MM_MODEM_GSM_USSD_STATE);
+
+ g_object_class_override_property (object_class,
+ MM_GENERIC_GSM_PROP_USSD_NETWORK_NOTIFICATION,
+ MM_MODEM_GSM_USSD_NETWORK_NOTIFICATION);
+
+ g_object_class_override_property (object_class,
+ MM_GENERIC_GSM_PROP_USSD_NETWORK_REQUEST,
+ MM_MODEM_GSM_USSD_NETWORK_REQUEST);
+
g_object_class_install_property
(object_class, MM_GENERIC_GSM_PROP_POWER_UP_CMD,
g_param_spec_string (MM_GENERIC_GSM_POWER_UP_CMD,
diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h
index de9dc89..5712660 100644
--- a/src/mm-generic-gsm.h
+++ b/src/mm-generic-gsm.h
@@ -17,6 +17,8 @@
#ifndef MM_GENERIC_GSM_H
#define MM_GENERIC_GSM_H
+#include <config.h>
+
#include "mm-modem-gsm.h"
#include "mm-modem-gsm-network.h"
#include "mm-modem-base.h"
@@ -46,7 +48,15 @@ typedef enum {
MM_GENERIC_GSM_PROP_SUPPORTED_MODES,
MM_GENERIC_GSM_PROP_INIT_CMD_OPTIONAL,
MM_GENERIC_GSM_PROP_ALLOWED_MODE,
- MM_GENERIC_GSM_PROP_ACCESS_TECHNOLOGY
+ MM_GENERIC_GSM_PROP_ACCESS_TECHNOLOGY,
+ MM_GENERIC_GSM_PROP_LOC_CAPABILITIES,
+ MM_GENERIC_GSM_PROP_LOC_ENABLED,
+ MM_GENERIC_GSM_PROP_LOC_SIGNAL,
+ MM_GENERIC_GSM_PROP_LOC_LOCATION,
+ MM_GENERIC_GSM_PROP_SIM_IDENTIFIER,
+ MM_GENERIC_GSM_PROP_USSD_STATE,
+ MM_GENERIC_GSM_PROP_USSD_NETWORK_REQUEST,
+ MM_GENERIC_GSM_PROP_USSD_NETWORK_NOTIFICATION,
} MMGenericGsmProp;
typedef enum {
@@ -110,13 +120,30 @@ typedef struct {
void (*get_access_technology) (MMGenericGsm *self,
MMModemUIntFn callback,
gpointer user_data);
+
+ /* Called by the generic class to get additional Location capabilities that
+ * subclasses may implement. The MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI
+ * capabilities is automatically provided by the generic class, and
+ * subclasses should return a bitfield of additional location capabilities
+ * they support in the callback here.
+ */
+ void (*loc_get_capabilities) (MMGenericGsm *self,
+ MMModemUIntFn callback,
+ gpointer user_data);
+
+ /* Called by the generic class to retrieve the SIM's ICCID */
+ void (*get_sim_iccid) (MMGenericGsm *self,
+ MMModemStringFn callback,
+ gpointer user_data);
} MMGenericGsmClass;
GType mm_generic_gsm_get_type (void);
MMModem *mm_generic_gsm_new (const char *device,
const char *driver,
- const char *plugin);
+ const char *plugin,
+ guint vendor,
+ guint product);
/* Private, for subclasses */
diff --git a/src/mm-log.c b/src/mm-log.c
new file mode 100644
index 0000000..bcf806a
--- /dev/null
+++ b/src/mm-log.c
@@ -0,0 +1,233 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ */
+
+#define _GNU_SOURCE
+#include <config.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mm-log.h"
+
+enum {
+ TS_FLAG_NONE = 0,
+ TS_FLAG_WALL,
+ TS_FLAG_REL
+};
+
+static gboolean ts_flags = TS_FLAG_NONE;
+static guint32 log_level = LOGL_INFO | LOGL_WARN | LOGL_ERR;
+static GTimeVal rel_start = { 0, 0 };
+static int logfd = -1;
+
+typedef struct {
+ guint32 num;
+ const char *name;
+} LogDesc;
+
+static const LogDesc level_descs[] = {
+ { LOGL_ERR, "ERR" },
+ { LOGL_WARN | LOGL_ERR, "WARN" },
+ { LOGL_INFO | LOGL_WARN | LOGL_ERR, "INFO" },
+ { LOGL_DEBUG | LOGL_INFO | LOGL_WARN | LOGL_ERR, "DEBUG" },
+ { 0, NULL }
+};
+
+void
+_mm_log (const char *loc,
+ const char *func,
+ guint32 level,
+ const char *fmt,
+ ...)
+{
+ va_list args;
+ char *msg;
+ GTimeVal tv;
+ char tsbuf[100] = { 0 };
+ char msgbuf[512] = { 0 };
+ int syslog_priority = LOG_INFO;
+ const char *prefix = NULL;
+ ssize_t ign;
+
+ if (!(log_level & level))
+ return;
+
+ va_start (args, fmt);
+ msg = g_strdup_vprintf (fmt, args);
+ va_end (args);
+
+ if (ts_flags == TS_FLAG_WALL) {
+ g_get_current_time (&tv);
+ snprintf (&tsbuf[0], sizeof (tsbuf), " [%09ld.%06ld]", tv.tv_sec, tv.tv_usec);
+ } else if (ts_flags == TS_FLAG_REL) {
+ time_t secs;
+ suseconds_t usecs;
+
+ g_get_current_time (&tv);
+ secs = tv.tv_sec - rel_start.tv_sec;
+ usecs = tv.tv_usec - rel_start.tv_usec;
+ if (usecs < 0) {
+ secs--;
+ usecs += 1000000;
+ }
+
+ snprintf (&tsbuf[0], sizeof (tsbuf), " [%06ld.%06ld]", secs, usecs);
+ }
+
+ if ((log_level & LOGL_DEBUG) && (level == LOGL_DEBUG))
+ prefix = "debug";
+ else if ((log_level & LOGL_INFO) && (level == LOGL_INFO))
+ prefix = "info";
+ else if ((log_level & LOGL_WARN) && (level == LOGL_WARN)) {
+ prefix = "warn";
+ syslog_priority = LOG_WARNING;
+ } else if ((log_level & LOGL_ERR) && (level == LOGL_ERR)) {
+ prefix = "err";
+ syslog_priority = LOG_ERR;
+ } else
+ g_warn_if_reached ();
+
+ if (prefix) {
+ if (log_level & LOGL_DEBUG)
+ snprintf (msgbuf, sizeof (msgbuf), "<%s>%s [%s] %s(): %s\n", prefix, tsbuf, loc, func, msg);
+ else
+ snprintf (msgbuf, sizeof (msgbuf), "<%s>%s %s\n", prefix, tsbuf, msg);
+
+ if (logfd < 0)
+ syslog (syslog_priority, "%s", msgbuf);
+ else {
+ ign = write (logfd, msgbuf, strlen (msgbuf));
+ if (ign) {} /* whatever; really shut up about unused result */
+
+ fsync (logfd); /* Make sure output is dumped to disk immediately */
+ }
+ }
+
+ g_free (msg);
+}
+
+static void
+log_handler (const gchar *log_domain,
+ GLogLevelFlags level,
+ const gchar *message,
+ gpointer ignored)
+{
+ int syslog_priority;
+ ssize_t ign;
+
+ switch (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;
+ }
+
+ if (logfd < 0)
+ syslog (syslog_priority, "%s", message);
+ else {
+ ign = write (logfd, message, strlen (message));
+ if (ign) {} /* whatever; really shut up about unused result */
+ }
+}
+
+gboolean
+mm_log_setup (const char *level,
+ const char *log_file,
+ gboolean show_timestamps,
+ gboolean rel_timestamps,
+ GError **error)
+{
+ /* levels */
+ if (level && strlen (level)) {
+ gboolean found = FALSE;
+ const LogDesc *diter;
+
+ for (diter = &level_descs[0]; diter->name; diter++) {
+ if (!strcasecmp (diter->name, level)) {
+ log_level = diter->num;
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ g_set_error (error, 0, 0, "Unknown log level '%s'", level);
+ return FALSE;
+ }
+ }
+
+ if (show_timestamps)
+ ts_flags = TS_FLAG_WALL;
+ else if (rel_timestamps)
+ ts_flags = TS_FLAG_REL;
+
+ /* Grab start time for relative timestamps */
+ g_get_current_time (&rel_start);
+
+ if (log_file == NULL)
+ openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PID | LOG_PERROR, LOG_DAEMON);
+ else {
+ logfd = open (log_file,
+ O_CREAT | O_APPEND | O_WRONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+ if (logfd < 0) {
+ g_set_error (error, 0, 0, "Failed to open log file: (%d) %s",
+ errno, strerror (errno));
+ return FALSE;
+ }
+ }
+
+ g_log_set_handler (G_LOG_DOMAIN,
+ G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
+ log_handler,
+ NULL);
+
+ return TRUE;
+}
+
+void
+mm_log_usr1 (void)
+{
+}
+
+void
+mm_log_shutdown (void)
+{
+ if (logfd < 0)
+ closelog ();
+ else
+ close (logfd);
+}
+
diff --git a/src/mm-log.h b/src/mm-log.h
new file mode 100644
index 0000000..9b0d875
--- /dev/null
+++ b/src/mm-log.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ */
+
+#ifndef MM_LOG_H
+#define MM_LOG_H
+
+#include <glib.h>
+
+/* Log levels */
+enum {
+ LOGL_ERR = 0x00000001,
+ LOGL_WARN = 0x00000002,
+ LOGL_INFO = 0x00000004,
+ LOGL_DEBUG = 0x00000008
+};
+
+#define mm_err(...) \
+ _mm_log (G_STRLOC, G_STRFUNC, LOGL_ERR, ## __VA_ARGS__ )
+
+#define mm_warn(...) \
+ _mm_log (G_STRLOC, G_STRFUNC, LOGL_WARN, ## __VA_ARGS__ )
+
+#define mm_info(...) \
+ _mm_log (G_STRLOC, G_STRFUNC, LOGL_INFO, ## __VA_ARGS__ )
+
+#define mm_dbg(...) \
+ _mm_log (G_STRLOC, G_STRFUNC, LOGL_DEBUG, ## __VA_ARGS__ )
+
+#define mm_log(level, ...) \
+ _mm_log (G_STRLOC, G_STRFUNC, level, ## __VA_ARGS__ )
+
+void _mm_log (const char *loc,
+ const char *func,
+ guint32 level,
+ const char *fmt,
+ ...) __attribute__((__format__ (__printf__, 4, 5)));
+
+gboolean mm_log_setup (const char *level,
+ const char *log_file,
+ gboolean show_ts,
+ gboolean rel_ts,
+ GError **error);
+
+void mm_log_usr1 (void);
+
+void mm_log_shutdown (void);
+
+#endif /* MM_LOG_H */
+
diff --git a/src/mm-manager.c b/src/mm-manager.c
index 1dd1902..561d427 100644
--- a/src/mm-manager.c
+++ b/src/mm-manager.c
@@ -24,6 +24,7 @@
#include "mm-manager.h"
#include "mm-errors.h"
#include "mm-plugin.h"
+#include "mm-log.h"
static gboolean impl_manager_enumerate_devices (MMManager *manager,
GPtrArray **devices,
@@ -112,9 +113,9 @@ load_plugin (const char *path)
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));
+ mm_info ("Loaded plugin %s", mm_plugin_get_name (plugin));
} else
- g_warning ("Could not load plugin %s: initialization failed", path);
+ mm_warn ("Could not load plugin %s: initialization failed", path);
out:
if (!plugin)
@@ -196,7 +197,7 @@ remove_modem (MMManager *manager, MMModem *modem)
device = mm_modem_get_device (modem);
g_assert (device);
- g_debug ("Removed modem %s", device);
+ mm_dbg ("Removed modem %s", device);
g_signal_emit (manager, signals[DEVICE_REMOVED], 0, modem);
g_hash_table_remove (priv->modems, device);
@@ -234,8 +235,8 @@ check_export_modem (MMManager *self, MMModem *modem)
SupportsInfo *info = value;
if (!strcmp (info->physdev_path, modem_physdev)) {
- g_debug ("(%s/%s): outstanding support task prevents export of %s",
- info->subsys, info->name, modem_physdev);
+ mm_dbg ("(%s/%s): outstanding support task prevents export of %s",
+ info->subsys, info->name, modem_physdev);
goto out;
}
}
@@ -248,19 +249,35 @@ check_export_modem (MMManager *self, MMModem *modem)
/* No outstanding port tasks, so if the modem is valid we can export it */
if (mm_modem_get_valid (modem)) {
- static guint32 id = 0;
+ static guint32 id = 0, vid = 0, pid = 0;
char *path, *data_device = NULL;
+ GUdevDevice *physdev;
+ const char *subsys = NULL;
path = g_strdup_printf (MM_DBUS_PATH"/Modems/%d", id++);
dbus_g_connection_register_g_object (priv->connection, path, G_OBJECT (modem));
g_object_set_data_full (G_OBJECT (modem), DBUS_PATH_TAG, path, (GDestroyNotify) g_free);
- g_debug ("Exported modem %s as %s", modem_physdev, path);
-
- g_object_get (G_OBJECT (modem), MM_MODEM_DATA_DEVICE, &data_device, NULL);
- g_debug ("(%s): data port is %s", path, data_device);
+ mm_dbg ("Exported modem %s as %s", modem_physdev, path);
+
+ physdev = g_udev_client_query_by_sysfs_path (priv->udev, modem_physdev);
+ if (physdev)
+ subsys = g_udev_device_get_subsystem (physdev);
+
+ g_object_get (G_OBJECT (modem),
+ MM_MODEM_DATA_DEVICE, &data_device,
+ MM_MODEM_HW_VID, &vid,
+ MM_MODEM_HW_PID, &pid,
+ NULL);
+ mm_dbg ("(%s): VID 0x%04X PID 0x%04X (%s)",
+ path, (vid & 0xFFFF), (pid & 0xFFFF),
+ subsys ? subsys : "unknown");
+ mm_dbg ("(%s): data port is %s", path, data_device);
g_free (data_device);
+ if (physdev)
+ g_object_unref (physdev);
+
g_signal_emit (self, signals[DEVICE_ADDED], 0, modem);
}
@@ -293,7 +310,7 @@ add_modem (MMManager *manager, MMModem *modem, MMPlugin *plugin)
g_hash_table_insert (priv->modems, g_strdup (device), modem);
g_object_set_data (G_OBJECT (modem), MANAGER_PLUGIN_TAG, plugin);
- g_debug ("Added modem %s", device);
+ mm_dbg ("Added modem %s", device);
g_signal_connect (modem, "notify::" MM_MODEM_VALID, G_CALLBACK (modem_valid), manager);
check_export_modem (manager, modem);
}
@@ -430,7 +447,7 @@ supports_defer_timeout (gpointer user_data)
existing = find_modem_for_device (info->manager, info->physdev_path);
- g_debug ("(%s): re-checking support...", info->name);
+ mm_dbg ("(%s): re-checking support...", info->name);
try_supports_port (info->manager,
MM_PLUGIN (info->cur_plugin->data),
existing,
@@ -462,9 +479,9 @@ try_supports_port (MMManager *manager,
supports_callback (plugin, info->subsys, info->name, 0, info);
break;
case MM_PLUGIN_SUPPORTS_PORT_DEFER:
- g_debug ("(%s): (%s) deferring support check",
- mm_plugin_get_name (plugin),
- info->name);
+ mm_dbg ("(%s): (%s) deferring support check",
+ mm_plugin_get_name (plugin),
+ info->name);
if (info->defer_id)
g_source_remove (info->defer_id);
@@ -533,22 +550,21 @@ do_grab_port (gpointer user_data)
type_name = "CDMA";
device = mm_modem_get_device (modem);
- g_message ("(%s): %s modem %s claimed port %s",
- mm_plugin_get_name (info->best_plugin),
- type_name,
- device,
- info->name);
+ mm_info ("(%s): %s modem %s claimed port %s",
+ mm_plugin_get_name (info->best_plugin),
+ type_name,
+ device,
+ info->name);
g_free (device);
add_modem (info->manager, modem, info->best_plugin);
} else {
- g_warning ("%s: plugin '%s' claimed to support %s/%s but couldn't: (%d) %s",
- __func__,
- mm_plugin_get_name (info->best_plugin),
- info->subsys,
- info->name,
- error ? error->code : -1,
- (error && error->message) ? error->message : "(unknown)");
+ mm_warn ("plugin '%s' claimed to support %s/%s but couldn't: (%d) %s",
+ mm_plugin_get_name (info->best_plugin),
+ info->subsys,
+ info->name,
+ error ? error->code : -1,
+ (error && error->message) ? error->message : "(unknown)");
modem = existing;
}
}
@@ -597,8 +613,8 @@ supports_callback (MMPlugin *plugin,
* support this port, but this plugin is clearly the right plugin
* since it claimed this port's physical modem, just drop the port.
*/
- g_debug ("(%s/%s): ignoring port unsupported by physical modem's plugin",
- info->subsys, info->name);
+ mm_dbg ("(%s/%s): ignoring port unsupported by physical modem's plugin",
+ info->subsys, info->name);
supports_cleanup (info->manager, info->subsys, info->name, existing);
return;
}
@@ -615,14 +631,14 @@ supports_callback (MMPlugin *plugin,
*/
next_plugin = existing_plugin;
} else {
- g_debug ("(%s/%s): plugin %p (%s) existing %p (%s) info->best %p (%s)",
- info->subsys, info->name,
- plugin,
- plugin ? mm_plugin_get_name (plugin) : "none",
- existing_plugin,
- existing_plugin ? mm_plugin_get_name (existing_plugin) : "none",
- info->best_plugin,
- info->best_plugin ? mm_plugin_get_name (info->best_plugin) : "none");
+ mm_dbg ("(%s/%s): plugin %p (%s) existing %p (%s) info->best %p (%s)",
+ info->subsys, info->name,
+ plugin,
+ plugin ? mm_plugin_get_name (plugin) : "none",
+ existing_plugin,
+ existing_plugin ? mm_plugin_get_name (existing_plugin) : "none",
+ info->best_plugin,
+ info->best_plugin ? mm_plugin_get_name (info->best_plugin) : "none");
g_assert_not_reached ();
}
} else {
@@ -717,7 +733,7 @@ device_added (MMManager *manager, GUdevDevice *device)
const char *subsys, *name, *physdev_path, *physdev_subsys;
SupportsInfo *info;
char *key;
- gboolean found;
+ gboolean found, is_candidate;
GUdevDevice *physdev = NULL;
MMPlugin *plugin;
MMModem *existing;
@@ -734,6 +750,17 @@ device_added (MMManager *manager, GUdevDevice *device)
if (strncmp (name, "tty", 3) == 0 && isdigit (name[3]))
return;
+ /* Ignore devices that aren't completely configured by udev yet. If
+ * ModemManager is started in parallel with udev, explicitly requesting
+ * devices may return devices for which not all udev rules have yet been
+ * applied (a bug in udev/gudev). Since we often need those rules to match
+ * the device to a specific ModemManager driver, we need to ensure that all
+ * rules have been processed before handling a device.
+ */
+ is_candidate = g_udev_device_get_property_as_boolean (device, "ID_MM_CANDIDATE");
+ if (!is_candidate)
+ return;
+
if (find_modem_for_port (manager, subsys, name))
return;
@@ -756,14 +783,14 @@ device_added (MMManager *manager, GUdevDevice *device)
&& strcmp (name, "lo")
&& strcmp (name, "tty")
&& !strstr (name, "virbr"))
- g_debug ("(%s/%s): could not get port's parent device", subsys, name);
+ mm_dbg ("(%s/%s): could not get port's parent device", subsys, name);
goto out;
}
/* Is the device blacklisted? */
if (g_udev_device_get_property_as_boolean (physdev, "ID_MM_DEVICE_IGNORE")) {
- g_debug ("(%s/%s): port's parent device is blacklisted", subsys, name);
+ mm_dbg ("(%s/%s): port's parent device is blacklisted", subsys, name);
goto out;
}
@@ -772,13 +799,13 @@ device_added (MMManager *manager, GUdevDevice *device)
if ( physdev_subsys
&& !strcmp (physdev_subsys, "platform")
&& !g_udev_device_get_property_as_boolean (physdev, "ID_MM_PLATFORM_DRIVER_PROBE")) {
- g_debug ("(%s/%s): port's parent platform driver is not whitelisted", subsys, name);
+ mm_dbg ("(%s/%s): port's parent platform driver is not whitelisted", subsys, name);
goto out;
}
physdev_path = g_udev_device_get_sysfs_path (physdev);
if (!physdev_path) {
- g_debug ("(%s/%s): could not get port's parent device sysfs path", subsys, name);
+ mm_dbg ("(%s/%s): could not get port's parent device sysfs path", subsys, name);
goto out;
}
@@ -809,7 +836,7 @@ device_removed (MMManager *manager, GUdevDevice *device)
MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager);
MMModem *modem;
const char *subsys, *name;
- char *key;
+ char *key, *modem_device;
SupportsInfo *info;
g_return_if_fail (device != NULL);
@@ -824,6 +851,9 @@ device_removed (MMManager *manager, GUdevDevice *device)
/* find_modem_for_port handles tty and net removal */
modem = find_modem_for_port (manager, subsys, name);
if (modem) {
+ modem_device = mm_modem_get_device (modem);
+ mm_info ("(%s/%s): released by modem %s", subsys, name, modem_device);
+ g_free (modem_device);
mm_modem_release_port (modem, subsys, name);
return;
}
@@ -838,10 +868,9 @@ device_removed (MMManager *manager, GUdevDevice *device)
*/
const char *sysfs_path = g_udev_device_get_sysfs_path (device);
- // g_debug ("Looking for a modem for removed device %s", sysfs_path);
modem = find_modem_for_device (manager, sysfs_path);
if (modem) {
- g_debug ("Removing modem claimed by removed device %s", sysfs_path);
+ mm_dbg ("Removing modem claimed by removed device %s", sysfs_path);
remove_modem (manager, modem);
return;
}
diff --git a/src/mm-modem-base.c b/src/mm-modem-base.c
index 0c39d2c..ee5e1c8 100644
--- a/src/mm-modem-base.c
+++ b/src/mm-modem-base.c
@@ -14,6 +14,7 @@
* Copyright (C) 2009 Red Hat, Inc.
*/
+#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -24,17 +25,19 @@
#include "mm-at-serial-port.h"
#include "mm-qcdm-serial-port.h"
#include "mm-errors.h"
-#include "mm-options.h"
+#include "mm-log.h"
#include "mm-properties-changed-signal.h"
#include "mm-callback-info.h"
#include "mm-modem-helpers.h"
static void modem_init (MMModem *modem_class);
+static void pc_init (MMPropertiesChanged *pc_class);
G_DEFINE_TYPE_EXTENDED (MMModemBase, mm_modem_base,
G_TYPE_OBJECT,
G_TYPE_FLAG_VALUE_ABSTRACT,
- G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init))
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_PROPERTIES_CHANGED, pc_init))
#define MM_MODEM_BASE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_BASE, MMModemBasePrivate))
@@ -43,15 +46,21 @@ typedef struct {
char *plugin;
char *device;
char *equipment_ident;
+ char *device_ident;
char *unlock_required;
guint32 unlock_retries;
guint32 ip_method;
gboolean valid;
MMModemState state;
+ guint vid;
+ guint pid;
char *manf;
char *model;
char *revision;
+ char *ati;
+ char *ati1;
+ char *gsn;
MMAuthProvider *authp;
@@ -139,15 +148,13 @@ mm_modem_base_add_port (MMModemBase *self,
if (!port)
return NULL;
- if (mm_options_debug ()) {
- device = mm_modem_get_device (MM_MODEM (self));
+ device = mm_modem_get_device (MM_MODEM (self));
+ mm_dbg ("(%s) type %s claimed by %s",
+ name,
+ mm_port_type_to_name (ptype),
+ device);
+ g_free (device);
- g_message ("(%s) type %s claimed by %s",
- name,
- mm_port_type_to_name (ptype),
- device);
- g_free (device);
- }
key = get_hash_key (subsys, name);
g_hash_table_insert (priv->ports, key, port);
return port;
@@ -156,10 +163,32 @@ mm_modem_base_add_port (MMModemBase *self,
gboolean
mm_modem_base_remove_port (MMModemBase *self, MMPort *port)
{
+ MMModemBasePrivate *priv;
+ char *device, *key, *name;
+ const char *type_name, *subsys;
+ gboolean removed;
+
g_return_val_if_fail (MM_IS_MODEM_BASE (self), FALSE);
g_return_val_if_fail (port != NULL, FALSE);
- return g_hash_table_remove (MM_MODEM_BASE_GET_PRIVATE (self)->ports, port);
+ priv = MM_MODEM_BASE_GET_PRIVATE (self);
+
+ name = g_strdup (mm_port_get_device (port));
+ subsys = mm_port_subsys_to_name (mm_port_get_subsys (port));
+ type_name = mm_port_type_to_name (mm_port_get_port_type (port));
+
+ key = get_hash_key (subsys, name);
+ removed = g_hash_table_remove (priv->ports, key);
+ if (removed) {
+ /* Port may have already been destroyed by removal from the hash */
+ device = mm_modem_get_device (MM_MODEM (self));
+ mm_dbg ("(%s) type %s removed from %s", name, type_name, device);
+ g_free (device);
+ }
+ g_free (key);
+ g_free (name);
+
+ return removed;
}
void
@@ -224,9 +253,9 @@ mm_modem_base_set_equipment_identifier (MMModemBase *self, const char *ident)
dbus_path = (const char *) g_object_get_data (G_OBJECT (self), DBUS_PATH_TAG);
if (dbus_path) {
if (priv->equipment_ident)
- g_message ("Modem %s: Equipment identifier set (%s)", dbus_path, priv->equipment_ident);
+ mm_info ("Modem %s: Equipment identifier set (%s)", dbus_path, priv->equipment_ident);
else
- g_message ("Modem %s: Equipment identifier not set", dbus_path);
+ mm_warn ("Modem %s: Equipment identifier not set", dbus_path);
}
g_object_notify (G_OBJECT (self), MM_MODEM_EQUIPMENT_IDENTIFIER);
@@ -265,9 +294,9 @@ mm_modem_base_set_unlock_required (MMModemBase *self, const char *unlock_require
dbus_path = (const char *) g_object_get_data (G_OBJECT (self), DBUS_PATH_TAG);
if (dbus_path) {
if (priv->unlock_required)
- g_message ("Modem %s: unlock required (%s)", dbus_path, priv->unlock_required);
+ mm_info ("Modem %s: unlock required (%s)", dbus_path, priv->unlock_required);
else
- g_message ("Modem %s: unlock no longer required", dbus_path);
+ mm_info ("Modem %s: unlock no longer required", dbus_path);
}
g_object_notify (G_OBJECT (self), MM_MODEM_UNLOCK_REQUIRED);
@@ -301,8 +330,13 @@ mm_modem_base_set_unlock_retries (MMModemBase *self, guint unlock_retries)
dbus_path = (const char *) g_object_get_data (G_OBJECT (self), DBUS_PATH_TAG);
if (dbus_path) {
- g_message ("Modem %s: # unlock retries for %s is %d",
- dbus_path, priv->unlock_required, priv->unlock_retries);
+ if (priv->unlock_required) {
+ mm_info ("Modem %s: # unlock retries for %s is %d",
+ dbus_path, priv->unlock_required, priv->unlock_retries);
+ } else {
+ mm_info ("Modem %s: # unlock retries is %d",
+ dbus_path, priv->unlock_retries);
+ }
}
g_object_notify (G_OBJECT (self), MM_MODEM_UNLOCK_RETRIES);
@@ -391,7 +425,7 @@ card_info_cache_invoke (MMCallbackInfo *info)
MMModemBase *self = MM_MODEM_BASE (info->modem);
MMModemBasePrivate *priv = MM_MODEM_BASE_GET_PRIVATE (self);
MMModemInfoFn callback = (MMModemInfoFn) info->callback;
- const char *manf, *cmanf, *model, *cmodel, *rev, *crev;
+ const char *manf, *cmanf, *model, *cmodel, *rev, *crev, *ati, *ati1, *gsn, *cgsn;
manf = mm_callback_info_get_data (info, "card-info-manf");
cmanf = mm_callback_info_get_data (info, "card-info-c-manf");
@@ -410,6 +444,31 @@ card_info_cache_invoke (MMCallbackInfo *info)
g_free (priv->revision);
priv->revision = g_strdup (crev ? crev : rev);
+ ati = mm_callback_info_get_data (info, "card-info-ati");
+ g_free (priv->ati);
+ priv->ati = g_strdup (ati);
+
+ ati1 = mm_callback_info_get_data (info, "card-info-ati1");
+ g_free (priv->ati1);
+ priv->ati1 = g_strdup (ati1);
+
+ gsn = mm_callback_info_get_data (info, "card-info-gsn");
+ cgsn = mm_callback_info_get_data (info, "card-info-c-gsn");
+ g_free (priv->gsn);
+ priv->gsn = g_strdup (cgsn ? cgsn : gsn);
+
+ /* Build up the device identifier */
+ g_free (priv->device_ident);
+ priv->device_ident = mm_create_device_identifier (priv->vid,
+ priv->pid,
+ priv->ati,
+ priv->ati1,
+ priv->gsn,
+ priv->revision,
+ priv->model,
+ priv->manf);
+ g_object_notify (G_OBJECT (self), MM_MODEM_DEVICE_IDENTIFIER);
+
callback (info->modem, priv->manf, priv->model, priv->revision, info->error, info->user_data);
}
@@ -418,35 +477,44 @@ info_item_done (MMCallbackInfo *info,
GString *response,
GError *error,
const char *tag,
+ const char *tag2,
const char *desc)
{
- const char *p;
+ const char *p = response->str;
if (!error) {
- p = mm_strip_tag (response->str, tag);
+ if (tag)
+ p = mm_strip_tag (p, tag);
+ if (tag2)
+ p = mm_strip_tag (p, tag2);
mm_callback_info_set_data (info, desc, strlen (p) ? g_strdup (p) : NULL, g_free);
}
mm_callback_info_chain_complete_one (info);
}
-#define GET_INFO_RESP_FN(func_name, tag, desc) \
+#define GET_INFO_RESP_FN(func_name, tag, tag2, desc) \
static void \
func_name (MMAtSerialPort *port, \
GString *response, \
GError *error, \
gpointer user_data) \
{ \
- info_item_done ((MMCallbackInfo *) user_data, response, error, tag , desc ); \
+ info_item_done ((MMCallbackInfo *) user_data, response, error, tag, tag2, desc ); \
}
-GET_INFO_RESP_FN(get_revision_done, "+GMR:", "card-info-revision")
-GET_INFO_RESP_FN(get_model_done, "+GMM:", "card-info-model")
-GET_INFO_RESP_FN(get_manf_done, "+GMI:", "card-info-manf")
+GET_INFO_RESP_FN(get_revision_done, "+GMR:", "AT+GMR", "card-info-revision")
+GET_INFO_RESP_FN(get_model_done, "+GMM:", "AT+GMM", "card-info-model")
+GET_INFO_RESP_FN(get_manf_done, "+GMI:", "AT+GMI", "card-info-manf")
+
+GET_INFO_RESP_FN(get_c_revision_done, "+CGMR:", "AT+CGMR", "card-info-c-revision")
+GET_INFO_RESP_FN(get_c_model_done, "+CGMM:", "AT+CGMM", "card-info-c-model")
+GET_INFO_RESP_FN(get_c_manf_done, "+CGMI:", "AT+CGMI", "card-info-c-manf")
-GET_INFO_RESP_FN(get_c_revision_done, "+CGMR:", "card-info-c-revision")
-GET_INFO_RESP_FN(get_c_model_done, "+CGMM:", "card-info-c-model")
-GET_INFO_RESP_FN(get_c_manf_done, "+CGMI:", "card-info-c-manf")
+GET_INFO_RESP_FN(get_ati_done, NULL, "ATI", "card-info-ati")
+GET_INFO_RESP_FN(get_ati1_done, NULL, "ATI1", "card-info-ati1")
+GET_INFO_RESP_FN(get_gsn_done, "+GSN:", "AT+GSN", "card-info-gsn")
+GET_INFO_RESP_FN(get_cgsn_done, "+CGSN:", "AT+CGSN", "card-info-c-gsn")
void
mm_modem_base_get_card_info (MMModemBase *self,
@@ -457,7 +525,6 @@ mm_modem_base_get_card_info (MMModemBase *self,
{
MMModemBasePrivate *priv;
MMCallbackInfo *info;
- MMModemState state;
gboolean cached = FALSE;
GError *error = port_error;
@@ -474,16 +541,8 @@ mm_modem_base_get_card_info (MMModemBase *self,
*/
if (priv->manf || priv->model || priv->revision)
cached = TRUE;
- else {
- state = mm_modem_get_state (MM_MODEM (self));
-
- if (port_error)
- error = g_error_copy (port_error);
- else if (state < MM_MODEM_STATE_ENABLING) {
- error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "The modem is not enabled.");
- }
- }
+ else if (port_error)
+ error = g_error_copy (port_error);
/* If we have cached info or an error, don't hit up the card */
if (cached || error) {
@@ -502,13 +561,19 @@ mm_modem_base_get_card_info (MMModemBase *self,
G_CALLBACK (callback),
user_data);
- mm_callback_info_chain_start (info, 6);
+ mm_callback_info_chain_start (info, 10);
+
mm_at_serial_port_queue_command_cached (port, "+GMI", 3, get_manf_done, info);
mm_at_serial_port_queue_command_cached (port, "+GMM", 3, get_model_done, info);
mm_at_serial_port_queue_command_cached (port, "+GMR", 3, get_revision_done, info);
mm_at_serial_port_queue_command_cached (port, "+CGMI", 3, get_c_manf_done, info);
mm_at_serial_port_queue_command_cached (port, "+CGMM", 3, get_c_model_done, info);
mm_at_serial_port_queue_command_cached (port, "+CGMR", 3, get_c_revision_done, info);
+
+ mm_at_serial_port_queue_command_cached (port, "I", 3, get_ati_done, info);
+ mm_at_serial_port_queue_command_cached (port, "I1", 3, get_ati1_done, info);
+ mm_at_serial_port_queue_command_cached (port, "+GSN", 3, get_gsn_done, info);
+ mm_at_serial_port_queue_command_cached (port, "+CGSN", 3, get_cgsn_done, info);
}
/*****************************************************************************/
@@ -562,15 +627,27 @@ mm_modem_base_init (MMModemBase *self)
mm_properties_changed_signal_register_property (G_OBJECT (self),
MM_MODEM_ENABLED,
+ NULL,
MM_MODEM_DBUS_INTERFACE);
mm_properties_changed_signal_register_property (G_OBJECT (self),
MM_MODEM_EQUIPMENT_IDENTIFIER,
+ NULL,
+ MM_MODEM_DBUS_INTERFACE);
+ mm_properties_changed_signal_register_property (G_OBJECT (self),
+ MM_MODEM_DEVICE_IDENTIFIER,
+ NULL,
MM_MODEM_DBUS_INTERFACE);
mm_properties_changed_signal_register_property (G_OBJECT (self),
MM_MODEM_UNLOCK_REQUIRED,
+ NULL,
MM_MODEM_DBUS_INTERFACE);
mm_properties_changed_signal_register_property (G_OBJECT (self),
MM_MODEM_UNLOCK_RETRIES,
+ NULL,
+ MM_MODEM_DBUS_INTERFACE);
+ mm_properties_changed_signal_register_property (G_OBJECT (self),
+ MM_MODEM_IP_METHOD,
+ NULL,
MM_MODEM_DBUS_INTERFACE);
}
@@ -581,6 +658,11 @@ modem_init (MMModem *modem_class)
modem_class->auth_finish = modem_auth_finish;
}
+static void
+pc_init (MMPropertiesChanged *pc_class)
+{
+}
+
static gboolean
is_enabled (MMModemState state)
{
@@ -621,9 +703,18 @@ set_property (GObject *object, guint prop_id,
case MM_MODEM_PROP_TYPE:
case MM_MODEM_PROP_ENABLED:
case MM_MODEM_PROP_EQUIPMENT_IDENTIFIER:
+ case MM_MODEM_PROP_DEVICE_IDENTIFIER:
case MM_MODEM_PROP_UNLOCK_REQUIRED:
case MM_MODEM_PROP_UNLOCK_RETRIES:
break;
+ case MM_MODEM_PROP_HW_VID:
+ /* Construct only */
+ priv->vid = g_value_get_uint (value);
+ break;
+ case MM_MODEM_PROP_HW_PID:
+ /* Construct only */
+ priv->pid = g_value_get_uint (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -667,12 +758,21 @@ get_property (GObject *object, guint prop_id,
case MM_MODEM_PROP_EQUIPMENT_IDENTIFIER:
g_value_set_string (value, priv->equipment_ident);
break;
+ case MM_MODEM_PROP_DEVICE_IDENTIFIER:
+ g_value_set_string (value, priv->device_ident);
+ break;
case MM_MODEM_PROP_UNLOCK_REQUIRED:
g_value_set_string (value, priv->unlock_required);
break;
case MM_MODEM_PROP_UNLOCK_RETRIES:
g_value_set_uint (value, priv->unlock_retries);
break;
+ case MM_MODEM_PROP_HW_VID:
+ g_value_set_uint (value, priv->vid);
+ break;
+ case MM_MODEM_PROP_HW_PID:
+ g_value_set_uint (value, priv->pid);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -692,7 +792,14 @@ finalize (GObject *object)
g_free (priv->plugin);
g_free (priv->device);
g_free (priv->equipment_ident);
+ g_free (priv->device_ident);
g_free (priv->unlock_required);
+ g_free (priv->manf);
+ g_free (priv->model);
+ g_free (priv->revision);
+ g_free (priv->ati);
+ g_free (priv->ati1);
+ g_free (priv->gsn);
G_OBJECT_CLASS (mm_modem_base_parent_class)->finalize (object);
}
@@ -750,6 +857,10 @@ mm_modem_base_class_init (MMModemBaseClass *klass)
MM_MODEM_EQUIPMENT_IDENTIFIER);
g_object_class_override_property (object_class,
+ MM_MODEM_PROP_DEVICE_IDENTIFIER,
+ MM_MODEM_DEVICE_IDENTIFIER);
+
+ g_object_class_override_property (object_class,
MM_MODEM_PROP_UNLOCK_REQUIRED,
MM_MODEM_UNLOCK_REQUIRED);
@@ -757,6 +868,14 @@ mm_modem_base_class_init (MMModemBaseClass *klass)
MM_MODEM_PROP_UNLOCK_RETRIES,
MM_MODEM_UNLOCK_RETRIES);
- mm_properties_changed_signal_new (object_class);
+ g_object_class_override_property (object_class,
+ MM_MODEM_PROP_HW_VID,
+ MM_MODEM_HW_VID);
+
+ g_object_class_override_property (object_class,
+ MM_MODEM_PROP_HW_PID,
+ MM_MODEM_HW_PID);
+
+ mm_properties_changed_signal_enable (object_class);
}
diff --git a/src/mm-modem-cdma.c b/src/mm-modem-cdma.c
index e80dc4e..722918e 100644
--- a/src/mm-modem-cdma.c
+++ b/src/mm-modem-cdma.c
@@ -26,6 +26,8 @@ static void impl_modem_cdma_get_signal_quality (MMModemCdma *modem, DBusGMethodI
static void impl_modem_cdma_get_esn (MMModemCdma *modem, DBusGMethodInvocation *context);
static void impl_modem_cdma_get_serving_system (MMModemCdma *modem, DBusGMethodInvocation *context);
static void impl_modem_cdma_get_registration_state (MMModemCdma *modem, DBusGMethodInvocation *context);
+static void impl_modem_cdma_activate (MMModemCdma *modem, DBusGMethodInvocation *context);
+static void impl_modem_cdma_activate_manual (MMModemCdma *modem, DBusGMethodInvocation *context);
#include "mm-modem-cdma-glue.h"
@@ -251,6 +253,39 @@ mm_modem_cdma_emit_signal_quality_changed (MMModemCdma *self, guint32 quality)
g_signal_emit (self, signals[SIGNAL_QUALITY], 0, quality);
}
+void mm_modem_cdma_activate(MMModemCdma *self, MMModemUIntFn callback,
+ gpointer user_data)
+{
+ g_return_if_fail (MM_IS_MODEM_CDMA (self));
+ g_return_if_fail (callback != NULL);
+
+ if (MM_MODEM_CDMA_GET_INTERFACE (self)->activate)
+ MM_MODEM_CDMA_GET_INTERFACE (self)->activate(self, callback, user_data);
+ else
+ uint_op_not_supported (MM_MODEM (self), callback, user_data);
+}
+
+static void impl_modem_cdma_activate(MMModemCdma *modem,
+ DBusGMethodInvocation *context)
+{
+ mm_modem_cdma_activate (modem, uint_call_done, context);
+}
+
+
+void mm_modem_cdma_activate_manual(MMModemCdma *self, MMModemUIntFn callback,
+ gpointer user_data) {
+ g_return_if_fail (MM_IS_MODEM_CDMA (self));
+ g_return_if_fail (callback != NULL);
+ if (MM_MODEM_CDMA_GET_INTERFACE (self)->activate_manual)
+ MM_MODEM_CDMA_GET_INTERFACE (self)->activate_manual(self, callback, user_data);
+ else
+ uint_op_not_supported (MM_MODEM (self), callback, user_data);
+}
+static void impl_modem_cdma_activate_manual (MMModemCdma *modem,
+ DBusGMethodInvocation *context) {
+ mm_modem_cdma_activate_manual(modem, uint_call_done, context);
+}
+
/*****************************************************************************/
static void
@@ -322,6 +357,15 @@ mm_modem_cdma_init (gpointer g_iface)
if (initialized)
return;
+ /* Properties */
+ g_object_interface_install_property
+ (g_iface,
+ g_param_spec_string (MM_MODEM_CDMA_MEID,
+ "MEID",
+ "MEID",
+ NULL,
+ G_PARAM_READABLE));
+
/* Signals */
signals[SIGNAL_QUALITY] =
g_signal_new ("signal-quality",
diff --git a/src/mm-modem-cdma.h b/src/mm-modem-cdma.h
index a7a626f..4d30386 100644
--- a/src/mm-modem-cdma.h
+++ b/src/mm-modem-cdma.h
@@ -35,6 +35,14 @@ typedef enum {
#define MM_MODEM_CDMA_REGISTRATION_STATE_CHANGED "registration-state-changed"
+#define MM_MODEM_CDMA_MEID "meid"
+
+typedef enum {
+ MM_MODEM_CDMA_PROP_FIRST = 0x1200,
+
+ MM_MODEM_CDMA_PROP_MEID = MM_MODEM_CDMA_PROP_FIRST,
+} MMModemCdmaProp;
+
typedef struct _MMModemCdma MMModemCdma;
typedef void (*MMModemCdmaServingSystemFn) (MMModemCdma *modem,
@@ -70,6 +78,18 @@ struct _MMModemCdma {
MMModemCdmaRegistrationStateFn callback,
gpointer user_data);
+ void (*activate) (MMModemCdma *self,
+ MMModemUIntFn callback,
+ gpointer user_data);
+
+ void (*activate_manual) (MMModemCdma *self,
+ MMModemUIntFn callback,
+ gpointer user_data);
+
+ void (*activate_manual_debug) (MMModemCdma *self,
+ MMModemUIntFn callback,
+ gpointer user_data);
+
/* Signals */
void (*signal_quality) (MMModemCdma *self,
guint32 quality);
@@ -97,6 +117,12 @@ void mm_modem_cdma_get_registration_state (MMModemCdma *self,
MMModemCdmaRegistrationStateFn callback,
gpointer user_data);
+void mm_modem_cdma_activate (MMModemCdma *self, MMModemUIntFn callback,
+ gpointer user_data);
+
+void mm_modem_cdma_activate_manual (MMModemCdma *self, MMModemUIntFn callback,
+ gpointer user_data);
+
/* Protected */
void mm_modem_cdma_emit_signal_quality_changed (MMModemCdma *self, guint32 new_quality);
diff --git a/src/mm-modem-gsm-card.c b/src/mm-modem-gsm-card.c
index e03b964..d04f014 100644
--- a/src/mm-modem-gsm-card.c
+++ b/src/mm-modem-gsm-card.c
@@ -581,6 +581,14 @@ mm_modem_gsm_card_init (gpointer g_iface)
g_object_interface_install_property
(g_iface,
+ g_param_spec_string (MM_MODEM_GSM_CARD_SIM_IDENTIFIER,
+ "SimIdentifier",
+ "An obfuscated identifier of the SIM",
+ NULL,
+ G_PARAM_READABLE));
+
+ g_object_interface_install_property
+ (g_iface,
g_param_spec_uint (MM_MODEM_GSM_CARD_SUPPORTED_BANDS,
"Supported Modes",
"Supported frequency bands of the card",
diff --git a/src/mm-modem-gsm-card.h b/src/mm-modem-gsm-card.h
index 584d734..e617d8f 100644
--- a/src/mm-modem-gsm-card.h
+++ b/src/mm-modem-gsm-card.h
@@ -26,6 +26,7 @@
#define MM_MODEM_GSM_CARD_SUPPORTED_BANDS "supported-bands"
#define MM_MODEM_GSM_CARD_SUPPORTED_MODES "supported-modes"
+#define MM_MODEM_GSM_CARD_SIM_IDENTIFIER "sim-identifier"
#define MM_MODEM_GSM_CARD_SIM_PIN "sim-pin"
#define MM_MODEM_GSM_CARD_SIM_PIN2 "sim-pin2"
diff --git a/src/mm-modem-gsm-network.c b/src/mm-modem-gsm-network.c
index 4cd6921..75ca7de 100644
--- a/src/mm-modem-gsm-network.c
+++ b/src/mm-modem-gsm-network.c
@@ -108,6 +108,8 @@ mm_modem_gsm_network_act_to_old_mode (MMModemGsmAccessTech act)
return MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_HSUPA;
else if (act & MM_MODEM_GSM_ACCESS_TECH_HSPA)
return MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_HSPA;
+ else if (act & MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS)
+ return MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_HSPA;
return MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_ANY;
}
diff --git a/src/mm-modem-gsm-ussd.c b/src/mm-modem-gsm-ussd.c
new file mode 100644
index 0000000..f90a845
--- /dev/null
+++ b/src/mm-modem-gsm-ussd.c
@@ -0,0 +1,378 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2010 Guido Guenther <agx@sigxcpu.org>
+ */
+
+#include <string.h>
+#include <dbus/dbus-glib.h>
+
+#include "mm-modem-gsm-ussd.h"
+#include "mm-errors.h"
+#include "mm-callback-info.h"
+#include "mm-marshal.h"
+
+static void impl_modem_gsm_ussd_initiate(MMModemGsmUssd *modem,
+ const char*command,
+ DBusGMethodInvocation *context);
+
+static void impl_modem_gsm_ussd_respond(MMModemGsmUssd *modem,
+ const char *response,
+ DBusGMethodInvocation *context);
+
+static void impl_modem_gsm_ussd_cancel(MMModemGsmUssd *modem,
+ DBusGMethodInvocation *context);
+
+#include "mm-modem-gsm-ussd-glue.h"
+
+
+/*****************************************************************************/
+
+static void
+str_call_done (MMModem *modem, const char *result, GError *error, gpointer user_data)
+{
+ DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
+
+ if (error)
+ dbus_g_method_return_error (context, error);
+ else
+ dbus_g_method_return (context, result);
+}
+
+static void
+str_call_not_supported (MMModemGsmUssd *self,
+ MMModemStringFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_string_new (MM_MODEM (self), callback, user_data);
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED,
+ "Operation not supported");
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+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
+async_call_not_supported (MMModemGsmUssd *self,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new (MM_MODEM (self), callback, user_data);
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED,
+ "Operation not supported");
+ mm_callback_info_schedule (info);
+}
+
+/*****************************************************************************/
+
+void
+mm_modem_gsm_ussd_initiate (MMModemGsmUssd *self,
+ const char *command,
+ MMModemStringFn callback,
+ gpointer user_data)
+{
+ g_return_if_fail (MM_IS_MODEM_GSM_USSD (self));
+ g_return_if_fail (command != NULL);
+ g_return_if_fail (callback != NULL);
+
+ if (MM_MODEM_GSM_USSD_GET_INTERFACE (self)->initiate)
+ MM_MODEM_GSM_USSD_GET_INTERFACE (self)->initiate(self, command, callback, user_data);
+ else
+ str_call_not_supported (self, callback, user_data);
+
+}
+
+void
+mm_modem_gsm_ussd_respond (MMModemGsmUssd *self,
+ const char *command,
+ MMModemStringFn callback,
+ gpointer user_data)
+{
+ g_return_if_fail (MM_IS_MODEM_GSM_USSD (self));
+ g_return_if_fail (command != NULL);
+ g_return_if_fail (callback != NULL);
+
+ if (MM_MODEM_GSM_USSD_GET_INTERFACE (self)->respond)
+ MM_MODEM_GSM_USSD_GET_INTERFACE (self)->respond(self, command, callback, user_data);
+ else
+ str_call_not_supported (self, callback, user_data);
+
+}
+
+void
+mm_modem_gsm_ussd_cancel (MMModemGsmUssd *self,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ g_return_if_fail (MM_IS_MODEM_GSM_USSD (self));
+ g_return_if_fail (callback != NULL);
+
+ if (MM_MODEM_GSM_USSD_GET_INTERFACE (self)->cancel)
+ MM_MODEM_GSM_USSD_GET_INTERFACE (self)->cancel(self, callback, user_data);
+ else
+ async_call_not_supported (self, callback, user_data);
+
+}
+
+/*****************************************************************************/
+
+typedef struct {
+ char *command;
+} UssdAuthInfo;
+
+static void
+ussd_auth_info_destroy (gpointer data)
+{
+ UssdAuthInfo *info = data;
+
+ g_free (info->command);
+ g_free (info);
+}
+
+static UssdAuthInfo *
+ussd_auth_info_new (const char* command)
+{
+ UssdAuthInfo *info;
+
+ info = g_malloc0 (sizeof (UssdAuthInfo));
+ info->command = g_strdup (command);
+
+ return info;
+}
+
+/*****************************************************************************/
+
+static void
+ussd_initiate_auth_cb (MMAuthRequest *req,
+ GObject *owner,
+ DBusGMethodInvocation *context,
+ gpointer user_data)
+{
+ MMModemGsmUssd *self = MM_MODEM_GSM_USSD (owner);
+ UssdAuthInfo *info = user_data;
+ GError *error = NULL;
+
+ /* Return any authorization error, otherwise initiate the USSD */
+ if (!mm_modem_auth_finish (MM_MODEM (self), req, &error))
+ goto done;
+
+ if (!info->command) {
+ error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Missing USSD command");
+ }
+
+done:
+ if (error) {
+ str_call_done (MM_MODEM (self), NULL, error, context);
+ g_error_free (error);
+ } else
+ mm_modem_gsm_ussd_initiate (self, info->command, str_call_done, context);
+}
+
+static void
+impl_modem_gsm_ussd_initiate (MMModemGsmUssd *modem,
+ const char *command,
+ DBusGMethodInvocation *context)
+{
+ GError *error = NULL;
+ UssdAuthInfo *info;
+
+ info = ussd_auth_info_new (command);
+
+ /* Make sure the caller is authorized to initiate the USSD */
+ if (!mm_modem_auth_request (MM_MODEM (modem),
+ MM_AUTHORIZATION_USSD,
+ context,
+ ussd_initiate_auth_cb,
+ info,
+ ussd_auth_info_destroy,
+ &error)) {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ }
+}
+
+static void
+ussd_respond_auth_cb (MMAuthRequest *req,
+ GObject *owner,
+ DBusGMethodInvocation *context,
+ gpointer user_data)
+{
+ MMModemGsmUssd *self = MM_MODEM_GSM_USSD (owner);
+ UssdAuthInfo *info = user_data;
+ GError *error = NULL;
+
+ /* Return any authorization error, otherwise respond to the USSD */
+ if (!mm_modem_auth_finish (MM_MODEM (self), req, &error))
+ goto done;
+
+ if (!info->command) {
+ error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Missing USSD command");
+ }
+
+done:
+ if (error) {
+ str_call_done (MM_MODEM (self), NULL, error, context);
+ g_error_free (error);
+ } else
+ mm_modem_gsm_ussd_respond (self, info->command, str_call_done, context);
+}
+
+static void
+impl_modem_gsm_ussd_respond (MMModemGsmUssd *modem,
+ const char *command,
+ DBusGMethodInvocation *context)
+{
+ GError *error = NULL;
+ UssdAuthInfo *info;
+
+ info = ussd_auth_info_new (command);
+
+ /* Make sure the caller is authorized to respond to the USSD */
+ if (!mm_modem_auth_request (MM_MODEM (modem),
+ MM_AUTHORIZATION_USSD,
+ context,
+ ussd_respond_auth_cb,
+ info,
+ ussd_auth_info_destroy,
+ &error)) {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ }
+}
+
+static void
+ussd_cancel_auth_cb (MMAuthRequest *req,
+ GObject *owner,
+ DBusGMethodInvocation *context,
+ gpointer user_data)
+{
+ MMModemGsmUssd *self = MM_MODEM_GSM_USSD (owner);
+ GError *error = NULL;
+
+ /* Return any authorization error, otherwise cancel the USSD */
+ mm_modem_auth_finish (MM_MODEM (self), req, &error);
+
+ if (error) {
+ str_call_done (MM_MODEM (self), NULL, error, context);
+ g_error_free (error);
+ } else
+ mm_modem_gsm_ussd_cancel (self, async_call_done, context);
+}
+
+static void
+impl_modem_gsm_ussd_cancel (MMModemGsmUssd *modem,
+ DBusGMethodInvocation *context)
+{
+ GError *error = NULL;
+ UssdAuthInfo *info;
+
+ info = ussd_auth_info_new (NULL);
+
+ /* Make sure the caller is authorized to cancel USSD */
+ if (!mm_modem_auth_request (MM_MODEM (modem),
+ MM_AUTHORIZATION_USSD,
+ context,
+ ussd_cancel_auth_cb,
+ info,
+ ussd_auth_info_destroy,
+ &error)) {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ }
+}
+
+/*****************************************************************************/
+
+static void
+mm_modem_gsm_ussd_init (gpointer g_iface)
+{
+ static gboolean initialized = FALSE;
+
+ if (initialized)
+ return;
+
+ /* Properties */
+ g_object_interface_install_property
+ (g_iface,
+ g_param_spec_string (MM_MODEM_GSM_USSD_STATE,
+ "State",
+ "Current state of USSD session",
+ NULL,
+ G_PARAM_READABLE));
+
+ g_object_interface_install_property
+ (g_iface,
+ g_param_spec_string (MM_MODEM_GSM_USSD_NETWORK_NOTIFICATION,
+ "NetworkNotification",
+ "Network initiated request, no response required",
+ NULL,
+ G_PARAM_READABLE));
+
+ g_object_interface_install_property
+ (g_iface,
+ g_param_spec_string (MM_MODEM_GSM_USSD_NETWORK_REQUEST,
+ "NetworkRequest",
+ "Network initiated request, reponse required",
+ NULL,
+ G_PARAM_READABLE));
+
+ initialized = TRUE;
+}
+
+GType
+mm_modem_gsm_ussd_get_type (void)
+{
+ static GType ussd_type = 0;
+
+ if (!G_UNLIKELY (ussd_type)) {
+ const GTypeInfo ussd_info = {
+ sizeof (MMModemGsmUssd), /* class_size */
+ mm_modem_gsm_ussd_init, /* base_init */
+ NULL, /* base_finalize */
+ NULL,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0, /* n_preallocs */
+ NULL
+ };
+
+ ussd_type = g_type_register_static (G_TYPE_INTERFACE,
+ "MMModemGsmUssd",
+ &ussd_info, 0);
+
+ g_type_interface_add_prerequisite (ussd_type, G_TYPE_OBJECT);
+ dbus_g_object_type_install_info (ussd_type, &dbus_glib_mm_modem_gsm_ussd_object_info);
+
+ dbus_g_object_type_register_shadow_property (ussd_type,
+ "State",
+ MM_MODEM_GSM_USSD_STATE);
+ }
+
+ return ussd_type;
+}
diff --git a/src/mm-modem-gsm-ussd.h b/src/mm-modem-gsm-ussd.h
new file mode 100644
index 0000000..c8f652b
--- /dev/null
+++ b/src/mm-modem-gsm-ussd.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2010 Guido Guenther <agx@sigxcpu.org>
+ */
+
+#ifndef MM_MODEM_GSM_USSD_H
+#define MM_MODEM_GSM_USSD_H
+
+#include <mm-modem.h>
+
+typedef enum {
+ MM_MODEM_GSM_USSD_STATE_IDLE = 0x00000000,
+ MM_MODEM_GSM_USSD_STATE_ACTIVE = 0x00000001,
+ MM_MODEM_GSM_USSD_STATE_USER_RESPONSE = 0x00000002,
+} MMModemGsmUssdState;
+
+#define MM_MODEM_GSM_USSD_STATE "ussd-state"
+#define MM_MODEM_GSM_USSD_NETWORK_NOTIFICATION "network-notification"
+#define MM_MODEM_GSM_USSD_NETWORK_REQUEST "network-request"
+
+#define MM_TYPE_MODEM_GSM_USSD (mm_modem_gsm_ussd_get_type ())
+#define MM_MODEM_GSM_USSD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_GSM_USSD, MMModemGsmUssd))
+#define MM_IS_MODEM_GSM_USSD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_GSM_USSD))
+#define MM_MODEM_GSM_USSD_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_MODEM_GSM_USSD, MMModemGsmUssd))
+
+#define MM_MODEM_GSM_USSD_DBUS_INTERFACE "org.freedesktop.ModemManager.Modem.Gsm.Ussd"
+
+typedef struct _MMModemGsmUssd MMModemGsmUssd;
+
+struct _MMModemGsmUssd {
+ GTypeInterface g_iface;
+
+ /* Methods */
+ void (*initiate) (MMModemGsmUssd *modem,
+ const char *command,
+ MMModemStringFn callback,
+ gpointer user_data);
+
+ void (*respond) (MMModemGsmUssd *modem,
+ const char *command,
+ MMModemStringFn callback,
+ gpointer user_data);
+
+ void (*cancel) (MMModemGsmUssd *modem,
+ MMModemFn callback,
+ gpointer user_data);
+};
+
+GType mm_modem_gsm_ussd_get_type (void);
+
+void mm_modem_gsm_ussd_initiate (MMModemGsmUssd *self,
+ const char *command,
+ MMModemStringFn callback,
+ gpointer user_data);
+
+void mm_modem_gsm_ussd_respond (MMModemGsmUssd *self,
+ const char *command,
+ MMModemStringFn callback,
+ gpointer user_data);
+
+void mm_modem_gsm_ussd_cancel (MMModemGsmUssd *self,
+ MMModemFn callback,
+ gpointer user_data);
+
+#endif /* MM_MODEM_GSM_USSD_H */
diff --git a/src/mm-modem-gsm.h b/src/mm-modem-gsm.h
index 6d9135a..a427d35 100644
--- a/src/mm-modem-gsm.h
+++ b/src/mm-modem-gsm.h
@@ -54,8 +54,9 @@ typedef enum {
MM_MODEM_GSM_ACCESS_TECH_HSDPA = 6, /* UTRAN w/HSDPA */
MM_MODEM_GSM_ACCESS_TECH_HSUPA = 7, /* UTRAN w/HSUPA */
MM_MODEM_GSM_ACCESS_TECH_HSPA = 8, /* UTRAN w/HSDPA and HSUPA */
+ MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS = 9, /* UTRAN w/HSPA+ */
- MM_MODEM_GSM_ACCESS_TECH_LAST = MM_MODEM_GSM_ACCESS_TECH_HSPA
+ MM_MODEM_GSM_ACCESS_TECH_LAST = MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS
} MMModemGsmAccessTech;
typedef enum {
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index 6e76f46..f13b4f2 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -15,6 +15,8 @@
*/
#include <config.h>
+#include <stdio.h>
+#include <ctype.h>
#include <glib.h>
#include <string.h>
#include <ctype.h>
@@ -23,6 +25,7 @@
#include "mm-errors.h"
#include "mm-modem-helpers.h"
+#include "mm-log.h"
const char *
mm_strip_tag (const char *str, const char *cmd)
@@ -240,10 +243,14 @@ mm_gsm_destroy_scan_data (gpointer data)
/* +CREG: <n>,<stat>,<lac>,<ci>,<AcT> (ETSI 27.007 solicited and some CREG=2 unsolicited) */
#define CREG6 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*(\\d{1,2})"
+/* +CREG: <n>,<stat>,<lac>,<ci>,<AcT?>,<something> (Samsung Wave S8500) */
+/* '<CR><LF>+CREG: 2,1,000B,2816, B, C2816<CR><LF><CR><LF>OK<CR><LF>' */
+#define CREG7 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*[^,\\s]*"
+
GPtrArray *
mm_gsm_creg_regex_get (gboolean solicited)
{
- GPtrArray *array = g_ptr_array_sized_new (6);
+ GPtrArray *array = g_ptr_array_sized_new (7);
GRegex *regex;
/* #1 */
@@ -294,6 +301,14 @@ mm_gsm_creg_regex_get (gboolean solicited)
g_assert (regex);
g_ptr_array_add (array, regex);
+ /* #7 */
+ if (solicited)
+ regex = g_regex_new (CREG7 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ else
+ regex = g_regex_new ("\\r\\n" CREG7 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ g_assert (regex);
+ g_ptr_array_add (array, regex);
+
return array;
}
@@ -783,7 +798,9 @@ mm_gsm_string_to_access_tech (const char *string)
/* Better technologies are listed first since modems sometimes say
* stuff like "GPRS/EDGE" and that should be handled as EDGE.
*/
- if (strcasestr (string, "HSPA"))
+ if (strcasestr (string, "HSPA+"))
+ return MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS;
+ else if (strcasestr (string, "HSPA"))
return MM_MODEM_GSM_ACCESS_TECH_HSPA;
else if (strcasestr (string, "HSDPA/HSUPA"))
return MM_MODEM_GSM_ACCESS_TECH_HSPA;
@@ -803,3 +820,278 @@ mm_gsm_string_to_access_tech (const char *string)
return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
}
+/*************************************************************************/
+
+char *
+mm_create_device_identifier (guint vid,
+ guint pid,
+ const char *ati,
+ const char *ati1,
+ const char *gsn,
+ const char *revision,
+ const char *model,
+ const char *manf)
+{
+ GString *devid, *msg = NULL;
+ GChecksum *sum;
+ char *p, *ret = NULL;
+ char str_vid[10], str_pid[10];
+
+ /* Build up the device identifier */
+ devid = g_string_sized_new (50);
+ if (ati)
+ g_string_append (devid, ati);
+ if (ati1) {
+ /* Only append "ATI1" if it's differnet than "ATI" */
+ if (!ati || (strcmp (ati, ati1) != 0))
+ g_string_append (devid, ati1);
+ }
+ if (gsn)
+ g_string_append (devid, gsn);
+ if (revision)
+ g_string_append (devid, revision);
+ if (model)
+ g_string_append (devid, model);
+ if (manf)
+ g_string_append (devid, manf);
+
+ if (!strlen (devid->str))
+ return NULL;
+
+ p = devid->str;
+ msg = g_string_sized_new (strlen (devid->str) + 17);
+
+ sum = g_checksum_new (G_CHECKSUM_SHA1);
+
+ if (vid) {
+ snprintf (str_vid, sizeof (str_vid) - 1, "%08x", vid);
+ g_checksum_update (sum, (const guchar *) &str_vid[0], strlen (str_vid));
+ g_string_append_printf (msg, "%08x", vid);
+ }
+ if (vid) {
+ snprintf (str_pid, sizeof (str_pid) - 1, "%08x", pid);
+ g_checksum_update (sum, (const guchar *) &str_pid[0], strlen (str_pid));
+ g_string_append_printf (msg, "%08x", pid);
+ }
+
+ while (*p) {
+ /* Strip spaces and linebreaks */
+ if (!isblank (*p) && !isspace (*p) && isascii (*p)) {
+ g_checksum_update (sum, (const guchar *) p, 1);
+ g_string_append_c (msg, *p);
+ }
+ p++;
+ }
+ ret = g_strdup (g_checksum_get_string (sum));
+ g_checksum_free (sum);
+
+ mm_dbg ("Device ID source '%s'", msg->str);
+ mm_dbg ("Device ID '%s'", ret);
+ g_string_free (msg, TRUE);
+
+ return ret;
+}
+
+/*************************************************************************/
+
+struct CindResponse {
+ char *desc;
+ guint idx;
+ gint min;
+ gint max;
+};
+
+static CindResponse *
+cind_response_new (const char *desc, guint idx, gint min, gint max)
+{
+ CindResponse *r;
+ char *p;
+
+ g_return_val_if_fail (desc != NULL, NULL);
+ g_return_val_if_fail (idx >= 0, NULL);
+
+ r = g_malloc0 (sizeof (CindResponse));
+
+ /* Strip quotes */
+ r->desc = p = g_malloc0 (strlen (desc) + 1);
+ while (*desc) {
+ if (*desc != '"' && !isspace (*desc))
+ *p++ = tolower (*desc);
+ desc++;
+ }
+
+ r->idx = idx;
+ r->max = max;
+ r->min = min;
+ return r;
+}
+
+static void
+cind_response_free (CindResponse *r)
+{
+ g_return_if_fail (r != NULL);
+
+ g_free (r->desc);
+ memset (r, 0, sizeof (CindResponse));
+ g_free (r);
+}
+
+const char *
+cind_response_get_desc (CindResponse *r)
+{
+ g_return_val_if_fail (r != NULL, NULL);
+
+ return r->desc;
+}
+
+guint
+cind_response_get_index (CindResponse *r)
+{
+ g_return_val_if_fail (r != NULL, 0);
+
+ return r->idx;
+}
+
+gint
+cind_response_get_min (CindResponse *r)
+{
+ g_return_val_if_fail (r != NULL, -1);
+
+ return r->min;
+}
+
+gint
+cind_response_get_max (CindResponse *r)
+{
+ g_return_val_if_fail (r != NULL, -1);
+
+ return r->max;
+}
+
+#define CIND_TAG "+CIND:"
+
+GHashTable *
+mm_parse_cind_test_response (const char *reply, GError **error)
+{
+ GHashTable *hash;
+ GRegex *r;
+ GMatchInfo *match_info;
+ guint idx = 1;
+
+ g_return_val_if_fail (reply != NULL, NULL);
+
+ /* Strip whitespace and response tag */
+ if (g_str_has_prefix (reply, CIND_TAG))
+ reply += strlen (CIND_TAG);
+ while (isspace (*reply))
+ reply++;
+
+ r = g_regex_new ("\\(([^,]*),\\((\\d+)[-,](\\d+)\\)", G_REGEX_UNGREEDY, 0, NULL);
+ if (!r) {
+ g_set_error_literal (error,
+ MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Could not parse scan results.");
+ return NULL;
+ }
+
+ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) cind_response_free);
+
+ if (g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, NULL)) {
+ while (g_match_info_matches (match_info)) {
+ CindResponse *resp;
+ char *desc, *tmp;
+ gint min = 0, max = 0;
+
+ desc = g_match_info_fetch (match_info, 1);
+
+ tmp = g_match_info_fetch (match_info, 2);
+ min = atoi (tmp);
+ g_free (tmp);
+
+ tmp = g_match_info_fetch (match_info, 3);
+ max = atoi (tmp);
+ g_free (tmp);
+
+ resp = cind_response_new (desc, idx++, min, max);
+ if (resp)
+ g_hash_table_insert (hash, g_strdup (resp->desc), resp);
+
+ g_free (desc);
+
+ g_match_info_next (match_info, NULL);
+ }
+ g_match_info_free (match_info);
+ }
+ g_regex_unref (r);
+
+ return hash;
+}
+
+GByteArray *
+mm_parse_cind_query_response(const char *reply, GError **error)
+{
+ GByteArray *array = NULL;
+ const char *p = reply;
+ GRegex *r = NULL;
+ GMatchInfo *match_info;
+ guint8 t = 0;
+
+ g_return_val_if_fail (reply != NULL, NULL);
+
+ if (!g_str_has_prefix (p, CIND_TAG)) {
+ g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Could not parse the +CIND response");
+ return NULL;
+ }
+
+ p += strlen (CIND_TAG);
+ while (isspace (*p))
+ p++;
+
+ r = g_regex_new ("(\\d+)[^0-9]+", G_REGEX_UNGREEDY, 0, NULL);
+ if (!r) {
+ g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Internal failure attempting to parse +CIND response");
+ return NULL;
+ }
+
+ if (!g_regex_match_full (r, p, strlen (p), 0, 0, &match_info, NULL)) {
+ g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Failure parsing the +CIND response");
+ goto done;
+ }
+
+ array = g_byte_array_sized_new (g_match_info_get_match_count (match_info));
+
+ /* Add a zero element so callers can use 1-based indexes returned by
+ * cind_response_get_index().
+ */
+ g_byte_array_append (array, &t, 1);
+
+ while (g_match_info_matches (match_info)) {
+ char *str;
+ gulong val;
+
+ str = g_match_info_fetch (match_info, 1);
+
+ errno = 0;
+ val = strtoul (str, NULL, 10);
+
+ t = 0;
+ if ((errno == 0) && (val < 255))
+ t = (guint8) val;
+ /* FIXME: indicate errors somehow? */
+ g_byte_array_append (array, &t, 1);
+
+ g_free (str);
+ g_match_info_next (match_info, NULL);
+ }
+ g_match_info_free (match_info);
+
+done:
+ if (r)
+ g_regex_unref (r);
+
+ return array;
+}
+
diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
index fb100bc..71ccaa5 100644
--- a/src/mm-modem-helpers.h
+++ b/src/mm-modem-helpers.h
@@ -59,5 +59,23 @@ gboolean mm_gsm_parse_cscs_support_response (const char *reply,
MMModemGsmAccessTech mm_gsm_string_to_access_tech (const char *string);
+char *mm_create_device_identifier (guint vid,
+ guint pid,
+ const char *ati,
+ const char *ati1,
+ const char *gsn,
+ const char *revision,
+ const char *model,
+ const char *manf);
+
+typedef struct CindResponse CindResponse;
+GHashTable *mm_parse_cind_test_response (const char *reply, GError **error);
+const char *cind_response_get_desc (CindResponse *r);
+guint cind_response_get_index (CindResponse *r);
+gint cind_response_get_min (CindResponse *r);
+gint cind_response_get_max (CindResponse *r);
+
+GByteArray *mm_parse_cind_query_response(const char *reply, GError **error);
+
#endif /* MM_MODEM_HELPERS_H */
diff --git a/src/mm-modem-location.c b/src/mm-modem-location.c
index 0018295..2dadd4e 100644
--- a/src/mm-modem-location.c
+++ b/src/mm-modem-location.c
@@ -257,7 +257,7 @@ mm_modem_location_init (gpointer g_iface)
g_param_spec_boxed (MM_MODEM_LOCATION_LOCATION,
"Location",
"Available location information",
- G_TYPE_HASH_TABLE,
+ MM_MODEM_LOCATION_PROP_TYPE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_interface_install_property
@@ -267,7 +267,8 @@ mm_modem_location_init (gpointer g_iface)
"Supported location information methods",
MM_MODEM_LOCATION_CAPABILITY_UNKNOWN,
MM_MODEM_LOCATION_CAPABILITY_GPS_NMEA
- | MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI,
+ | MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI
+ | MM_MODEM_LOCATION_CAPABILITY_GPS_RAW,
MM_MODEM_LOCATION_CAPABILITY_UNKNOWN,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
diff --git a/src/mm-modem-location.h b/src/mm-modem-location.h
index dd622f1..7b8399f 100644
--- a/src/mm-modem-location.h
+++ b/src/mm-modem-location.h
@@ -23,6 +23,10 @@
#define MM_IS_MODEM_LOCATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_LOCATION))
#define MM_MODEM_LOCATION_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_MODEM_LOCATION, MMModemLocation))
+#define MM_MODEM_LOCATION_DBUS_INTERFACE "org.freedesktop.ModemManager.Modem.Location"
+
+#define MM_MODEM_LOCATION_PROP_TYPE (dbus_g_type_get_map ("GHashTable", G_TYPE_UINT, G_TYPE_VALUE))
+
#define MM_MODEM_LOCATION_CAPABILITIES "location-capabilities"
#define MM_MODEM_LOCATION_ENABLED "location-enabled"
#define MM_MODEM_LOCATION_SIGNALS_LOCATION "signals-location"
@@ -32,8 +36,9 @@ typedef enum {
MM_MODEM_LOCATION_CAPABILITY_UNKNOWN = 0x00000000,
MM_MODEM_LOCATION_CAPABILITY_GPS_NMEA = 0x00000001,
MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI = 0x00000002,
+ MM_MODEM_LOCATION_CAPABILITY_GPS_RAW = 0x00000004,
- MM_MODEM_LOCATION_CAPABILITY_LAST = MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI
+ MM_MODEM_LOCATION_CAPABILITY_LAST = MM_MODEM_LOCATION_CAPABILITY_GPS_RAW
} MMModemLocationCapabilities;
typedef struct _MMModemLocation MMModemLocation;
diff --git a/src/mm-modem.c b/src/mm-modem.c
index 221c9ea..f823472 100644
--- a/src/mm-modem.c
+++ b/src/mm-modem.c
@@ -18,7 +18,7 @@
#include <string.h>
#include <dbus/dbus-glib.h>
#include "mm-modem.h"
-#include "mm-options.h"
+#include "mm-log.h"
#include "mm-errors.h"
#include "mm-callback-info.h"
#include "mm-marshal.h"
@@ -28,6 +28,7 @@ static void impl_modem_connect (MMModem *modem, const char *number, DBusGMethodI
static void impl_modem_disconnect (MMModem *modem, DBusGMethodInvocation *context);
static void impl_modem_get_ip4_config (MMModem *modem, DBusGMethodInvocation *context);
static void impl_modem_get_info (MMModem *modem, DBusGMethodInvocation *context);
+static void impl_modem_reset (MMModem *modem, DBusGMethodInvocation *context);
static void impl_modem_factory_reset (MMModem *modem, const char *code, DBusGMethodInvocation *context);
#include "mm-modem-glue.h"
@@ -478,6 +479,56 @@ impl_modem_get_info (MMModem *modem,
/*****************************************************************************/
static void
+reset_auth_cb (MMAuthRequest *req,
+ GObject *owner,
+ DBusGMethodInvocation *context,
+ gpointer user_data)
+{
+ MMModem *self = MM_MODEM (owner);
+ GError *error = NULL;
+
+ /* Return any authorization error, otherwise try to reset the modem */
+ if (!mm_modem_auth_finish (self, req, &error)) {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ } else
+ mm_modem_reset (self, async_call_done, context);
+}
+
+static void
+impl_modem_reset (MMModem *modem, DBusGMethodInvocation *context)
+{
+ GError *error = NULL;
+
+ /* Make sure the caller is authorized to reset the device */
+ if (!mm_modem_auth_request (MM_MODEM (modem),
+ MM_AUTHORIZATION_DEVICE_CONTROL,
+ context,
+ reset_auth_cb,
+ NULL, NULL,
+ &error)) {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ }
+}
+
+void
+mm_modem_reset (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)->reset)
+ MM_MODEM_GET_INTERFACE (self)->reset (self, callback, user_data);
+ else
+ async_op_not_supported (self, callback, user_data);
+}
+
+/*****************************************************************************/
+
+static void
factory_reset_auth_cb (MMAuthRequest *req,
GObject *owner,
DBusGMethodInvocation *context,
@@ -704,22 +755,10 @@ mm_modem_set_state (MMModem *self,
dbus_path = (const char *) g_object_get_data (G_OBJECT (self), DBUS_PATH_TAG);
if (dbus_path) {
- if (mm_options_debug ()) {
- GTimeVal tv;
-
- g_get_current_time (&tv);
- g_debug ("<%ld.%ld> Modem %s: state changed (%s -> %s)",
- tv.tv_sec,
- tv.tv_usec,
- dbus_path,
- state_to_string (old_state),
- state_to_string (new_state));
- } else {
- g_message ("Modem %s: state changed (%s -> %s)",
- dbus_path,
- state_to_string (old_state),
- state_to_string (new_state));
- }
+ mm_info ("Modem %s: state changed (%s -> %s)",
+ dbus_path,
+ state_to_string (old_state),
+ state_to_string (new_state));
}
}
}
@@ -832,7 +871,7 @@ mm_modem_init (gpointer g_iface)
MM_MODEM_IP_METHOD_PPP,
MM_MODEM_IP_METHOD_DHCP,
MM_MODEM_IP_METHOD_PPP,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ G_PARAM_READWRITE));
g_object_interface_install_property
(g_iface,
@@ -870,6 +909,14 @@ mm_modem_init (gpointer g_iface)
g_object_interface_install_property
(g_iface,
+ g_param_spec_string (MM_MODEM_DEVICE_IDENTIFIER,
+ "DeviceIdentifier",
+ "A best-effort identifer of the device",
+ NULL,
+ G_PARAM_READABLE));
+
+ g_object_interface_install_property
+ (g_iface,
g_param_spec_string (MM_MODEM_UNLOCK_REQUIRED,
"UnlockRequired",
"Whether or not the modem requires an unlock "
@@ -885,6 +932,22 @@ mm_modem_init (gpointer g_iface)
0, G_MAXUINT32, 0,
G_PARAM_READABLE));
+ g_object_interface_install_property
+ (g_iface,
+ g_param_spec_uint (MM_MODEM_HW_VID,
+ "Hardware vendor ID",
+ "Hardware vendor ID",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_interface_install_property
+ (g_iface,
+ g_param_spec_uint (MM_MODEM_HW_PID,
+ "Hardware product ID",
+ "Hardware product ID",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
/* Signals */
g_signal_new ("state-changed",
iface_type,
diff --git a/src/mm-modem.h b/src/mm-modem.h
index 0915180..7f0bf58 100644
--- a/src/mm-modem.h
+++ b/src/mm-modem.h
@@ -11,7 +11,7 @@
* GNU General Public License for more details:
*
* Copyright (C) 2008 - 2009 Novell, Inc.
- * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 - 2010 Red Hat, Inc.
*/
#ifndef MM_MODEM_H
@@ -40,7 +40,9 @@ typedef enum {
} MMModemState;
typedef enum {
- MM_MODEM_STATE_REASON_NONE = 0
+ MM_MODEM_STATE_REASON_NONE = 0,
+ MM_MODEM_STATE_REASON_USER_REQUESTED,
+ MM_MODEM_STATE_REASON_SUSPEND
} MMModemStateReason;
#define DBUS_PATH_TAG "dbus-path"
@@ -59,11 +61,14 @@ typedef enum {
#define MM_MODEM_IP_METHOD "ip-method"
#define MM_MODEM_ENABLED "enabled"
#define MM_MODEM_EQUIPMENT_IDENTIFIER "equipment-identifier"
+#define MM_MODEM_DEVICE_IDENTIFIER "device-identifier"
#define MM_MODEM_UNLOCK_REQUIRED "unlock-required"
#define MM_MODEM_UNLOCK_RETRIES "unlock-retries"
#define MM_MODEM_VALID "valid" /* not exported */
#define MM_MODEM_PLUGIN "plugin" /* not exported */
#define MM_MODEM_STATE "state" /* not exported */
+#define MM_MODEM_HW_VID "hw-vid" /* not exported */
+#define MM_MODEM_HW_PID "hw-pid" /* not exported */
#define MM_MODEM_TYPE_UNKNOWN 0
#define MM_MODEM_TYPE_GSM 1
@@ -87,7 +92,10 @@ typedef enum {
MM_MODEM_PROP_ENABLED,
MM_MODEM_PROP_EQUIPMENT_IDENTIFIER,
MM_MODEM_PROP_UNLOCK_REQUIRED,
- MM_MODEM_PROP_UNLOCK_RETRIES
+ MM_MODEM_PROP_UNLOCK_RETRIES,
+ MM_MODEM_PROP_DEVICE_IDENTIFIER,
+ MM_MODEM_PROP_HW_VID, /* Not exported */
+ MM_MODEM_PROP_HW_PID /* Not exported */
} MMModemProp;
typedef struct _MMModem MMModem;
@@ -188,6 +196,10 @@ struct _MMModem {
MMAuthRequest *req,
GError **error);
+ void (*reset) (MMModem *self,
+ MMModemFn callback,
+ gpointer user_data);
+
void (*factory_reset) (MMModem *self,
const char *code,
MMModemFn callback,
@@ -251,6 +263,10 @@ void mm_modem_set_charset (MMModem *self,
MMModemFn callback,
gpointer user_data);
+void mm_modem_reset (MMModem *self,
+ MMModemFn callback,
+ gpointer user_data);
+
void mm_modem_factory_reset (MMModem *self,
const char *code,
MMModemFn callback,
diff --git a/src/mm-options.c b/src/mm-options.c
deleted file mode 100644
index 7bbeefd..0000000
--- a/src/mm-options.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details:
- *
- * Copyright (C) 2008 Novell, Inc.
- */
-
-#include <stdlib.h>
-#include <glib.h>
-#include "mm-options.h"
-
-static gboolean debug = FALSE;
-
-void
-mm_options_parse (int argc, char *argv[])
-{
- GOptionContext *opt_ctx;
- GError *error = NULL;
- 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);
- exit (1);
- }
-
- g_option_context_free (opt_ctx);
-}
-
-void
-mm_options_set_debug (gboolean enabled)
-{
- debug = enabled;
-}
-
-gboolean
-mm_options_debug (void)
-{
- return debug;
-}
diff --git a/src/mm-options.h b/src/mm-options.h
deleted file mode 100644
index ce33e27..0000000
--- a/src/mm-options.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details:
- *
- * Copyright (C) 2008 Novell, Inc.
- */
-
-#ifndef MM_OPTIONS_H
-#define MM_OPTIONS_H
-
-void mm_options_parse (int argc, char *argv[]);
-void mm_options_set_debug (gboolean enabled);
-gboolean mm_options_debug (void);
-
-#endif /* MM_OPTIONS_H */
diff --git a/src/mm-plugin-base.c b/src/mm-plugin-base.c
index 80d0f90..8d32e2a 100644
--- a/src/mm-plugin-base.c
+++ b/src/mm-plugin-base.c
@@ -18,6 +18,8 @@
#include <stdio.h>
#include <stdlib.h>
+
+#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
@@ -34,6 +36,7 @@
#include "mm-utils.h"
#include "libqcdm/src/commands.h"
#include "libqcdm/src/utils.h"
+#include "mm-log.h"
static void plugin_init (MMPlugin *plugin_class);
@@ -48,6 +51,8 @@ G_DEFINE_TYPE_EXTENDED (MMPluginBase, mm_plugin_base, G_TYPE_OBJECT,
*/
static GHashTable *cached_caps = NULL;
+/* Virtual port corresponding to the embeded modem */
+static gchar *virtual_port[] = {"smd0", NULL};
typedef struct {
char *name;
@@ -803,9 +808,9 @@ try_open (gpointer user_data)
task_priv->full_id = g_signal_connect (task_priv->probe_port, "buffer-full",
G_CALLBACK (port_buffer_full), task);
- g_debug ("(%s): probe requested by plugin '%s'",
- g_udev_device_get_name (port),
- mm_plugin_get_name (MM_PLUGIN (task_priv->plugin)));
+ mm_dbg ("(%s): probe requested by plugin '%s'",
+ g_udev_device_get_name (port),
+ mm_plugin_get_name (MM_PLUGIN (task_priv->plugin)));
mm_serial_port_flash (MM_SERIAL_PORT (task_priv->probe_port), 100, TRUE, flash_done, task);
}
@@ -890,8 +895,8 @@ mm_plugin_base_get_device_ids (MMPluginBase *self,
guint16 *product)
{
MMPluginBasePrivate *priv;
- GUdevDevice *device = NULL;
- const char *vid, *pid;
+ GUdevDevice *device = NULL, *parent = NULL;
+ const char *vid = NULL, *pid = NULL, *parent_subsys;
gboolean success = FALSE;
g_return_val_if_fail (self != NULL, FALSE);
@@ -909,8 +914,37 @@ mm_plugin_base_get_device_ids (MMPluginBase *self,
if (!device)
goto out;
- vid = g_udev_device_get_property (device, "ID_VENDOR_ID");
- if (!vid || (strlen (vid) != 4))
+ parent = g_udev_device_get_parent (device);
+ if (parent) {
+ parent_subsys = g_udev_device_get_subsystem (parent);
+ if (parent_subsys) {
+ if (!strcmp (parent_subsys, "bluetooth")) {
+ /* Bluetooth devices report the VID/PID of the BT adapter here,
+ * which isn't really what we want. Just return null IDs instead.
+ */
+ success = TRUE;
+ goto out;
+ } else if (!strcmp (parent_subsys, "pcmcia")) {
+ /* For PCMCIA devices we need to grab the PCMCIA subsystem's
+ * manfid and cardid, since any IDs on the tty device itself
+ * may be from PCMCIA controller or something else.
+ */
+ vid = g_udev_device_get_sysfs_attr (parent, "manf_id");
+ pid = g_udev_device_get_sysfs_attr (parent, "card_id");
+ if (!vid || !pid)
+ goto out;
+ }
+ }
+ }
+
+ if (!vid)
+ vid = g_udev_device_get_property (device, "ID_VENDOR_ID");
+ if (!vid)
+ goto out;
+
+ if (strncmp (vid, "0x", 2) == 0)
+ vid += 2;
+ if (strlen (vid) != 4)
goto out;
if (vendor) {
@@ -918,8 +952,16 @@ mm_plugin_base_get_device_ids (MMPluginBase *self,
*vendor |= (guint16) ((utils_hex2byte (vid) & 0xFF) << 8);
}
- pid = g_udev_device_get_property (device, "ID_MODEL_ID");
- if (!pid || (strlen (pid) != 4)) {
+ if (!pid)
+ pid = g_udev_device_get_property (device, "ID_MODEL_ID");
+ if (!pid) {
+ *vendor = 0;
+ goto out;
+ }
+
+ if (strncmp (pid, "0x", 2) == 0)
+ pid += 2;
+ if (strlen (pid) != 4) {
*vendor = 0;
goto out;
}
@@ -934,6 +976,8 @@ mm_plugin_base_get_device_ids (MMPluginBase *self,
out:
if (device)
g_object_unref (device);
+ if (parent)
+ g_object_unref (parent);
return success;
}
@@ -980,6 +1024,20 @@ get_driver_name (GUdevDevice *device)
return ret;
}
+static gboolean
+device_file_exists(const char *name)
+{
+ char *devfile;
+ struct stat s;
+ int result;
+
+ devfile = g_strdup_printf ("/dev/%s", name);
+ result = stat (devfile, &s);
+ g_free (devfile);
+
+ return (0 == result) ? TRUE : FALSE;
+}
+
static MMPluginSupportsResult
supports_port (MMPlugin *plugin,
const char *subsys,
@@ -995,6 +1053,7 @@ supports_port (MMPlugin *plugin,
char *driver = NULL, *key = NULL;
MMPluginBaseSupportsTask *task;
MMPluginSupportsResult result = MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ int idx;
key = get_key (subsys, name);
task = g_hash_table_lookup (priv->tasks, key);
@@ -1007,6 +1066,19 @@ supports_port (MMPlugin *plugin,
if (!port)
goto out;
+ // Detect any modems accessible through the list of virtual ports
+ for (idx = 0; virtual_port[idx]; idx++) {
+ if (strcmp(name, virtual_port[idx]))
+ continue;
+ if (!device_file_exists(virtual_port[idx]))
+ continue;
+
+ task = supports_task_new (self, port, physdev_path, "virtual", callback, callback_data);
+ g_assert (task);
+ g_hash_table_insert (priv->tasks, g_strdup (key), g_object_ref (task));
+ goto find_plugin;
+ }
+
driver = get_driver_name (port);
if (!driver)
goto out;
@@ -1015,6 +1087,7 @@ supports_port (MMPlugin *plugin,
g_assert (task);
g_hash_table_insert (priv->tasks, g_strdup (key), g_object_ref (task));
+find_plugin:
result = MM_PLUGIN_BASE_GET_CLASS (self)->supports_port (self, existing, task);
if (result != MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS) {
/* If the plugin doesn't support the port at all, the supports task is
diff --git a/src/mm-port.c b/src/mm-port.c
index b2018fe..a1291d0 100644
--- a/src/mm-port.c
+++ b/src/mm-port.c
@@ -19,7 +19,7 @@
#include <string.h>
#include "mm-port.h"
-#include "mm-options.h"
+#include "mm-log.h"
G_DEFINE_TYPE (MMPort, mm_port, G_TYPE_OBJECT)
@@ -47,6 +47,20 @@ typedef struct {
/*****************************************************************************/
const char *
+mm_port_subsys_to_name (MMPortSubsys psubsys)
+{
+ switch (psubsys) {
+ case MM_PORT_SUBSYS_TTY:
+ return "tty";
+ case MM_PORT_SUBSYS_NET:
+ return "net";
+ default:
+ break;
+ }
+ return "(unknown)";
+}
+
+const char *
mm_port_type_to_name (MMPortType ptype)
{
switch (ptype) {
@@ -161,16 +175,10 @@ mm_port_set_connected (MMPort *self, gboolean connected)
if (priv->connected != connected) {
priv->connected = connected;
g_object_notify (G_OBJECT (self), MM_PORT_CONNECTED);
- if (mm_options_debug()) {
- GTimeVal tv;
-
- g_get_current_time (&tv);
- g_debug ("<%ld.%ld> (%s): port now %s",
- tv.tv_sec,
- tv.tv_usec,
- priv->device,
- connected ? "connected" : "disconnected");
- }
+
+ mm_dbg ("(%s): port now %s",
+ priv->device,
+ connected ? "connected" : "disconnected");
}
}
diff --git a/src/mm-port.h b/src/mm-port.h
index 43f78f4..4bcffd4 100644
--- a/src/mm-port.h
+++ b/src/mm-port.h
@@ -78,5 +78,7 @@ void mm_port_set_connected (MMPort *self, gboolean connected);
const char * mm_port_type_to_name (MMPortType ptype);
+const char * mm_port_subsys_to_name (MMPortSubsys psubsys);
+
#endif /* MM_PORT_H */
diff --git a/src/mm-properties-changed-signal.c b/src/mm-properties-changed-signal.c
index b7f3672..4408e80 100644
--- a/src/mm-properties-changed-signal.c
+++ b/src/mm-properties-changed-signal.c
@@ -11,7 +11,7 @@
* GNU General Public License for more details:
*
* Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2008 - 2009 Red Hat, Inc.
+ * Copyright (C) 2008 - 2010 Red Hat, Inc.
*/
#include <string.h>
@@ -20,17 +20,28 @@
#include <dbus/dbus-glib.h>
#include "mm-marshal.h"
#include "mm-properties-changed-signal.h"
+#include "mm-properties-changed-glue.h"
+#include "mm-log.h"
-#define DBUS_TYPE_G_MAP_OF_VARIANT (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
+#define DBUS_TYPE_G_MAP_OF_VARIANT (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
+#define DBUS_TYPE_G_ARRAY_OF_STRING (dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING))
-#define PC_SIGNAL_NAME "mm-properties-changed"
+#define MM_PC_SIGNAL_NAME "mm-properties-changed"
+#define DBUS_PC_SIGNAL_NAME "properties-changed"
#define MM_DBUS_PROPERTY_CHANGED "MM_DBUS_PROPERTY_CHANGED"
+/*****************************************************************************/
+
+typedef struct {
+ char *real_property;
+ char *interface;
+} ChangeInfo;
+
typedef struct {
/* Whitelist of GObject property names for which changes will be emitted
* over the bus.
*
- * Mapping of {property-name -> dbus-interface}
+ * Mapping of {property-name -> ChangeInfo}
*/
GHashTable *registered;
@@ -42,7 +53,6 @@ typedef struct {
*/
GHashTable *hash;
- gulong signal_id;
guint idle_id;
} PropertiesChangedInfo;
@@ -55,6 +65,17 @@ destroy_value (gpointer data)
g_slice_free (GValue, val);
}
+static void
+change_info_free (gpointer data)
+{
+ ChangeInfo *info = data;
+
+ g_free (info->real_property);
+ g_free (info->interface);
+ memset (info, 0, sizeof (ChangeInfo));
+ g_free (info);
+}
+
static PropertiesChangedInfo *
properties_changed_info_new (void)
{
@@ -62,7 +83,7 @@ properties_changed_info_new (void)
info = g_slice_new0 (PropertiesChangedInfo);
- info->registered = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ info->registered = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, change_info_free);
info->hash = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) g_hash_table_destroy);
@@ -124,20 +145,23 @@ properties_changed (gpointer data)
while (g_hash_table_iter_next (&iter, &key, &value)) {
const char *interface = (const char *) key;
GHashTable *props = (GHashTable *) value;
+ GPtrArray *ignore = g_ptr_array_new ();
#ifdef DEBUG
{
char buf[2048] = { 0, };
g_hash_table_foreach (props, add_to_string, &buf);
- g_message ("%s: %s -> (%s) %s", __func__,
- G_OBJECT_TYPE_NAME (object),
- interface,
- buf);
+ mm_dbg ("%s: %s -> (%s) %s", __func__,
+ G_OBJECT_TYPE_NAME (object),
+ interface,
+ buf);
}
#endif
/* Send the PropertiesChanged signal */
- g_signal_emit (object, info->signal_id, 0, interface, props);
+ g_signal_emit_by_name (object, MM_PC_SIGNAL_NAME, interface, props);
+ g_signal_emit_by_name (object, DBUS_PC_SIGNAL_NAME, interface, props, ignore);
+ g_ptr_array_free (ignore, TRUE);
}
g_hash_table_remove_all (info->hash);
@@ -191,8 +215,6 @@ get_properties_changed_info (GObject *object)
if (!info) {
info = properties_changed_info_new ();
g_object_set_data_full (object, MM_DBUS_PROPERTY_CHANGED, info, properties_changed_info_destroy);
- info->signal_id = g_signal_lookup (PC_SIGNAL_NAME, G_OBJECT_TYPE (object));
- g_assert (info->signal_id);
}
g_assert (info);
@@ -204,23 +226,23 @@ notify (GObject *object, GParamSpec *pspec)
{
GHashTable *interfaces;
PropertiesChangedInfo *info;
- const char *interface;
+ ChangeInfo *ch_info;
GValue *value;
info = get_properties_changed_info (object);
- interface = g_hash_table_lookup (info->registered, pspec->name);
- if (!interface)
+ ch_info = g_hash_table_lookup (info->registered, pspec->name);
+ if (!ch_info)
return;
/* Check if there are other changed properties for this interface already,
* otherwise create a new hash table for all changed properties for this
* D-Bus interface.
*/
- interfaces = g_hash_table_lookup (info->hash, interface);
+ interfaces = g_hash_table_lookup (info->hash, ch_info->interface);
if (!interfaces) {
interfaces = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, destroy_value);
- g_hash_table_insert (info->hash, g_strdup (interface), interfaces);
+ g_hash_table_insert (info->hash, g_strdup (ch_info->interface), interfaces);
}
/* Now put the changed property value into the hash table of changed values
@@ -229,7 +251,9 @@ notify (GObject *object, GParamSpec *pspec)
value = g_slice_new0 (GValue);
g_value_init (value, pspec->value_type);
g_object_get_property (object, pspec->name, value);
- g_hash_table_insert (interfaces, uscore_to_wincaps (pspec->name), value);
+
+ /* Use real property name, which takes shadow properties into accound */
+ g_hash_table_insert (interfaces, uscore_to_wincaps (ch_info->real_property), value);
if (!info->idle_id)
info->idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, properties_changed, object, idle_id_reset);
@@ -237,11 +261,12 @@ notify (GObject *object, GParamSpec *pspec)
void
mm_properties_changed_signal_register_property (GObject *object,
- const char *property,
+ const char *gobject_property,
+ const char *real_property,
const char *interface)
{
PropertiesChangedInfo *info;
- const char *tmp;
+ ChangeInfo *ch_info;
/* All exported properties need to be registered explicitly for now since
* dbus-glib doesn't expose any method to find out the properties registered
@@ -249,28 +274,79 @@ mm_properties_changed_signal_register_property (GObject *object,
*/
info = get_properties_changed_info (object);
- tmp = g_hash_table_lookup (info->registered, property);
- if (tmp) {
+ ch_info = g_hash_table_lookup (info->registered, gobject_property);
+ if (ch_info) {
g_warning ("%s: property '%s' already registerd on interface '%s'",
- __func__, property, tmp);
- } else
- g_hash_table_insert (info->registered, g_strdup (property), g_strdup (interface));
+ __func__, gobject_property, ch_info->interface);
+ } else {
+ ch_info = g_malloc0 (sizeof (ChangeInfo));
+ ch_info->real_property = g_strdup (real_property ? real_property : gobject_property);
+ ch_info->interface = g_strdup (interface);
+ g_hash_table_insert (info->registered, g_strdup (gobject_property), ch_info);
+ }
}
-guint
-mm_properties_changed_signal_new (GObjectClass *object_class)
+void
+mm_properties_changed_signal_enable (GObjectClass *object_class)
{
- guint id;
-
object_class->notify = notify;
+}
+
+/*****************************************************************************/
- id = g_signal_new (PC_SIGNAL_NAME,
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL,
- mm_marshal_VOID__STRING_BOXED,
- G_TYPE_NONE, 2, G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT);
+static void
+mm_properties_changed_init (gpointer g_iface)
+{
+ static gboolean initialized = FALSE;
- return id;
+ if (initialized)
+ return;
+
+ g_signal_new (MM_PC_SIGNAL_NAME,
+ G_TYPE_FROM_INTERFACE (g_iface),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL,
+ mm_marshal_VOID__STRING_BOXED,
+ G_TYPE_NONE, 2, G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT);
+
+ g_signal_new (DBUS_PC_SIGNAL_NAME,
+ G_TYPE_FROM_INTERFACE (g_iface),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL,
+ mm_marshal_VOID__STRING_BOXED_BOXED,
+ G_TYPE_NONE, 3,
+ G_TYPE_STRING,
+ DBUS_TYPE_G_MAP_OF_VARIANT,
+ DBUS_TYPE_G_ARRAY_OF_STRING);
+
+ initialized = TRUE;
}
+GType
+mm_properties_changed_get_type (void)
+{
+ static GType pc_type = 0;
+
+ if (!G_UNLIKELY (pc_type)) {
+ const GTypeInfo pc_info = {
+ sizeof (MMPropertiesChanged), /* class_size */
+ mm_properties_changed_init, /* base_init */
+ NULL, /* base_finalize */
+ NULL,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0, /* n_preallocs */
+ NULL
+ };
+
+ pc_type = g_type_register_static (G_TYPE_INTERFACE,
+ "MMPropertiesChanged",
+ &pc_info, 0);
+
+ g_type_interface_add_prerequisite (pc_type, G_TYPE_OBJECT);
+ dbus_g_object_type_install_info (pc_type, &dbus_glib_mm_properties_changed_object_info);
+ }
+
+ return pc_type;
+}
diff --git a/src/mm-properties-changed-signal.h b/src/mm-properties-changed-signal.h
index 60e71b9..a6d0f3e 100644
--- a/src/mm-properties-changed-signal.h
+++ b/src/mm-properties-changed-signal.h
@@ -11,7 +11,7 @@
* GNU General Public License for more details:
*
* Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2008 - 2009 Red Hat, Inc.
+ * Copyright (C) 2008 - 2010 Red Hat, Inc.
*/
#ifndef _MM_PROPERTIES_CHANGED_SIGNAL_H_
@@ -19,10 +19,22 @@
#include <glib-object.h>
-guint mm_properties_changed_signal_new (GObjectClass *object_class);
+#define MM_TYPE_PROPERTIES_CHANGED (mm_properties_changed_get_type ())
+#define MM_PROPERTIES_CHANGED(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PROPERTIES_CHANGED, MMPropertiesChanged))
+#define MM_IS_PROPERTIES_CHANGED(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PROPERTIES_CHANGED))
+#define MM_PROPERTIES_CHANGED_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_PROPERTIES_CHANGED, MMPropertiesChanged))
+
+typedef struct {
+ GTypeInterface g_iface;
+} MMPropertiesChanged;
+
+GType mm_properties_changed_get_type (void);
+
+void mm_properties_changed_signal_enable (GObjectClass *object_class);
void mm_properties_changed_signal_register_property (GObject *object,
- const char *property,
+ const char *gobject_property,
+ const char *real_property,
const char *interface);
#endif /* _MM_PROPERTIES_CHANGED_SIGNAL_H_ */
diff --git a/src/mm-qcdm-serial-port.c b/src/mm-qcdm-serial-port.c
index 1ce27e7..e467f2a 100644
--- a/src/mm-qcdm-serial-port.c
+++ b/src/mm-qcdm-serial-port.c
@@ -21,9 +21,9 @@
#include "mm-qcdm-serial-port.h"
#include "mm-errors.h"
-#include "mm-options.h"
#include "libqcdm/src/com.h"
#include "libqcdm/src/utils.h"
+#include "mm-log.h"
G_DEFINE_TYPE (MMQcdmSerialPort, mm_qcdm_serial_port, MM_TYPE_SERIAL_PORT)
@@ -37,22 +37,38 @@ typedef struct {
/*****************************************************************************/
static gboolean
-parse_response (MMSerialPort *port, GByteArray *response, GError **error)
+find_qcdm_start (GByteArray *response, gsize *start)
{
- int i;
+ int i, last = -1;
- /* Look for the QCDM packet termination character; if we found it, treat
- * the buffer as a qcdm command.
+ /* Look for 3 bytes and a QCDM frame marker, ie enough data for a valid
+ * frame. There will usually be three cases here; (1) a QCDM frame
+ * starting with data and terminated by 0x7E, and (2) a QCDM frame starting
+ * with 0x7E and ending with 0x7E, and (3) a non-QCDM frame that still
+ * uses HDLC framing (like Sierra CnS) that starts and ends with 0x7E.
*/
for (i = 0; i < response->len; i++) {
- if (response->data[i] == 0x7E)
- return TRUE;
+ if (response->data[i] == 0x7E) {
+ if (i > last + 3) {
+ /* Got a full QCDM frame; 3 non-0x7E bytes and a terminator */
+ if (start)
+ *start = last + 1;
+ return TRUE;
+ }
+
+ /* Save position of the last QCDM frame marker */
+ last = i;
+ }
}
-
- /* Otherwise, need more data from the device */
return FALSE;
}
+static gboolean
+parse_response (MMSerialPort *port, GByteArray *response, GError **error)
+{
+ return find_qcdm_start (response, NULL);
+}
+
static gsize
handle_response (MMSerialPort *port,
GByteArray *response,
@@ -64,41 +80,49 @@ handle_response (MMSerialPort *port,
GByteArray *unescaped = NULL;
GError *dm_error = NULL;
gsize used = 0;
+ gsize start = 0;
+ gboolean success = FALSE, more = FALSE;
+ gsize unescaped_len = 0;
+
+ if (error)
+ goto callback;
+
+ /* Get the offset into the buffer of where the QCDM frame starts */
+ if (!find_qcdm_start (response, &start)) {
+ g_set_error_literal (&dm_error,
+ MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Failed to parse QCDM packet.");
+ /* Discard the unparsable data */
+ used = response->len;
+ goto callback;
+ }
- /* Ignore empty frames */
- if (response->len > 0 && response->data[0] == 0x7E)
- return 1;
-
- if (!error) {
- gboolean more = FALSE, success;
- gsize unescaped_len = 0;
-
- /* FIXME: don't munge around with byte array internals */
- unescaped = g_byte_array_sized_new (1024);
- success = dm_decapsulate_buffer ((const char *) response->data,
- response->len,
- (char *) unescaped->data,
- 1024,
- &unescaped_len,
- &used,
- &more);
- if (!success) {
- g_set_error_literal (&dm_error,
- MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Failed to unescape QCDM packet.");
- g_byte_array_free (unescaped, TRUE);
- unescaped = NULL;
- } else if (more) {
- /* Need more data; we shouldn't have gotten here since the parse
- * function checks for the end-of-frame marker, but whatever.
- */
- return 0;
- } else {
- /* Successfully decapsulated the DM command */
- unescaped->len = (guint) unescaped_len;
- }
+ /* FIXME: don't munge around with byte array internals */
+ unescaped = g_byte_array_sized_new (1024);
+ success = dm_decapsulate_buffer ((const char *) (response->data + start),
+ response->len - start,
+ (char *) unescaped->data,
+ 1024,
+ &unescaped_len,
+ &used,
+ &more);
+ if (!success) {
+ g_set_error_literal (&dm_error,
+ MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Failed to unescape QCDM packet.");
+ g_byte_array_free (unescaped, TRUE);
+ unescaped = NULL;
+ } else if (more) {
+ /* Need more data; we shouldn't have gotten here since the parse
+ * function checks for the end-of-frame marker, but whatever.
+ */
+ return 0;
+ } else {
+ /* Successfully decapsulated the DM command */
+ unescaped->len = (guint) unescaped_len;
}
+callback:
response_callback (MM_QCDM_SERIAL_PORT (port),
unescaped,
dm_error ? dm_error : error,
@@ -106,8 +130,9 @@ handle_response (MMSerialPort *port,
if (unescaped)
g_byte_array_free (unescaped, TRUE);
+ g_clear_error (&dm_error);
- return used;
+ return start + used;
}
/*****************************************************************************/
@@ -157,7 +182,6 @@ debug_log (MMSerialPort *port, const char *prefix, const char *buf, gsize len)
{
static GString *debug = NULL;
const char *s = buf;
- GTimeVal tv;
if (!debug)
debug = g_string_sized_new (512);
@@ -167,12 +191,7 @@ debug_log (MMSerialPort *port, const char *prefix, const char *buf, gsize len)
while (len--)
g_string_append_printf (debug, " %02x", (guint8) (*s++ & 0xFF));
- g_get_current_time (&tv);
- g_debug ("<%ld.%ld> (%s): %s",
- tv.tv_sec,
- tv.tv_usec,
- mm_port_get_device (MM_PORT (port)),
- debug->str);
+ mm_dbg ("(%s): %s", mm_port_get_device (MM_PORT (port)), debug->str);
g_string_truncate (debug, 0);
}
@@ -196,6 +215,23 @@ mm_qcdm_serial_port_new (const char *name, MMPortType ptype)
NULL));
}
+MMQcdmSerialPort *
+mm_qcdm_serial_port_new_fd (int fd, MMPortType ptype)
+{
+ MMQcdmSerialPort *port;
+ char *name;
+
+ name = g_strdup_printf ("port%d", fd);
+ port = MM_QCDM_SERIAL_PORT (g_object_new (MM_TYPE_QCDM_SERIAL_PORT,
+ MM_PORT_DEVICE, name,
+ MM_PORT_SUBSYS, MM_PORT_SUBSYS_TTY,
+ MM_PORT_TYPE, ptype,
+ MM_SERIAL_PORT_FD, fd,
+ NULL));
+ g_free (name);
+ return port;
+}
+
static void
mm_qcdm_serial_port_init (MMQcdmSerialPort *self)
{
diff --git a/src/mm-qcdm-serial-port.h b/src/mm-qcdm-serial-port.h
index e70e124..2786ee8 100644
--- a/src/mm-qcdm-serial-port.h
+++ b/src/mm-qcdm-serial-port.h
@@ -50,6 +50,8 @@ GType mm_qcdm_serial_port_get_type (void);
MMQcdmSerialPort *mm_qcdm_serial_port_new (const char *name, MMPortType ptype);
+MMQcdmSerialPort *mm_qcdm_serial_port_new_fd (int fd, MMPortType ptype);
+
void mm_qcdm_serial_port_queue_command (MMQcdmSerialPort *self,
GByteArray *command,
guint32 timeout_seconds,
diff --git a/src/mm-serial-parsers.c b/src/mm-serial-parsers.c
index 7c9598e..75bcce4 100644
--- a/src/mm-serial-parsers.c
+++ b/src/mm-serial-parsers.c
@@ -19,6 +19,7 @@
#include "mm-serial-parsers.h"
#include "mm-errors.h"
+#include "mm-log.h"
/* Clean up the response by removing control characters like <CR><LF> etc */
static void
@@ -33,6 +34,13 @@ response_clean (GString *response)
s -= 2;
}
+ /* Contains duplicate '<CR><CR>' */
+ s = response->str;
+ while ((response->len >= 2) && (*s == '\r') && (*(s + 1) == '\r')) {
+ g_string_erase (response, 0, 1);
+ s = response->str;
+ }
+
/* Starts with one or more '<CR><LF>' */
s = response->str;
while ((response->len >= 2) && (*s == '\r') && (*(s + 1) == '\n')) {
@@ -167,7 +175,7 @@ mm_serial_parser_v0_parse (gpointer data,
response_clean (response);
if (local_error) {
- g_debug ("Got failure code %d: %s", local_error->code, local_error->message);
+ mm_dbg ("Got failure code %d: %s", local_error->code, local_error->message);
g_propagate_error (error, local_error);
}
@@ -192,6 +200,7 @@ typedef struct {
GRegex *regex_connect;
GRegex *regex_cme_error;
GRegex *regex_cme_error_str;
+ GRegex *regex_ezx_error;
GRegex *regex_unknown_error;
GRegex *regex_connect_failed;
} MMSerialParserV1;
@@ -208,6 +217,7 @@ mm_serial_parser_v1_new (void)
parser->regex_connect = g_regex_new ("\\r\\nCONNECT.*\\r\\n", flags, 0, NULL);
parser->regex_cme_error = g_regex_new ("\\r\\n\\+CME ERROR: (\\d+)\\r\\n$", flags, 0, NULL);
parser->regex_cme_error_str = g_regex_new ("\\r\\n\\+CME ERROR: ([^\\n\\r]+)\\r\\n$", flags, 0, NULL);
+ parser->regex_ezx_error = g_regex_new ("\\r\\n\\MODEM ERROR: (\\d+)\\r\\n$", flags, 0, NULL);
parser->regex_unknown_error = g_regex_new ("\\r\\n(ERROR)|(COMMAND NOT SUPPORT)\\r\\n$", flags, 0, NULL);
parser->regex_connect_failed = g_regex_new ("\\r\\n(NO CARRIER)|(BUSY)|(NO ANSWER)|(NO DIALTONE)\\r\\n$", flags, 0, NULL);
@@ -273,6 +283,19 @@ mm_serial_parser_v1_parse (gpointer data,
goto done;
}
+ /* Motorola EZX errors */
+ found = g_regex_match_full (parser->regex_ezx_error,
+ response->str, response->len,
+ 0, 0, &match_info, NULL);
+ if (found) {
+ str = g_match_info_fetch (match_info, 1);
+ g_assert (str);
+ local_error = mm_mobile_error_for_code (MM_MOBILE_ERROR_UNKNOWN);
+ g_free (str);
+ g_match_info_free (match_info);
+ goto done;
+ }
+
/* Last resort; unknown error */
found = g_regex_match_full (parser->regex_unknown_error,
response->str, response->len,
@@ -314,7 +337,7 @@ done:
response_clean (response);
if (local_error) {
- g_debug ("Got failure code %d: %s", local_error->code, local_error->message);
+ mm_dbg ("Got failure code %d: %s", local_error->code, local_error->message);
g_propagate_error (error, local_error);
}
@@ -332,6 +355,7 @@ mm_serial_parser_v1_destroy (gpointer data)
g_regex_unref (parser->regex_connect);
g_regex_unref (parser->regex_cme_error);
g_regex_unref (parser->regex_cme_error_str);
+ g_regex_unref (parser->regex_ezx_error);
g_regex_unref (parser->regex_unknown_error);
g_regex_unref (parser->regex_connect_failed);
diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c
index ed44167..bf2a98a 100644
--- a/src/mm-serial-port.c
+++ b/src/mm-serial-port.c
@@ -26,10 +26,11 @@
#include <errno.h>
#include <sys/ioctl.h>
#include <string.h>
+#include <linux/serial.h>
#include "mm-serial-port.h"
#include "mm-errors.h"
-#include "mm-options.h"
+#include "mm-log.h"
static gboolean mm_serial_port_queue_process (gpointer data);
@@ -42,6 +43,7 @@ enum {
PROP_PARITY,
PROP_STOPBITS,
PROP_SEND_DELAY,
+ PROP_FD,
LAST_PROP
};
@@ -150,10 +152,10 @@ mm_serial_port_print_config (MMSerialPort *port, const char *detail)
return;
}
- g_message ("*** %s (%s): (%s) baud rate: %d (%s)",
- __func__, detail, mm_port_get_device (MM_PORT (port)),
- stbuf.c_cflag & CBAUD,
- baud_to_string (stbuf.c_cflag & CBAUD));
+ mm_info ("(%s): (%s) baud rate: %d (%s)",
+ detail, mm_port_get_device (MM_PORT (port)),
+ stbuf.c_cflag & CBAUD,
+ baud_to_string (stbuf.c_cflag & CBAUD));
}
#endif
@@ -348,7 +350,7 @@ serial_debug (MMSerialPort *self, const char *prefix, const char *buf, gsize len
{
g_return_if_fail (len > 0);
- if (mm_options_debug () && MM_SERIAL_PORT_GET_CLASS (self)->debug_log)
+ if (MM_SERIAL_PORT_GET_CLASS (self)->debug_log)
MM_SERIAL_PORT_GET_CLASS (self)->debug_log (self, prefix, buf, len);
}
@@ -684,6 +686,7 @@ mm_serial_port_open (MMSerialPort *self, GError **error)
MMSerialPortPrivate *priv;
char *devfile;
const char *device;
+ struct serial_struct sinfo;
g_return_val_if_fail (MM_IS_SERIAL_PORT (self), FALSE);
@@ -696,11 +699,15 @@ mm_serial_port_open (MMSerialPort *self, GError **error)
goto success;
}
- g_message ("(%s) opening serial device...", device);
- devfile = g_strdup_printf ("/dev/%s", device);
- errno = 0;
- priv->fd = open (devfile, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
- g_free (devfile);
+ mm_info ("(%s) opening serial port...", device);
+
+ /* Only open a new file descriptor if we weren't given one already */
+ if (priv->fd < 0) {
+ devfile = g_strdup_printf ("/dev/%s", device);
+ errno = 0;
+ priv->fd = open (devfile, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
+ g_free (devfile);
+ }
if (priv->fd < 0) {
/* nozomi isn't ready yet when the port appears, and it'll return
@@ -733,6 +740,15 @@ mm_serial_port_open (MMSerialPort *self, GError **error)
if (!MM_SERIAL_PORT_GET_CLASS (self)->config_fd (self, priv->fd, error))
goto error;
+ /* Don't wait for pending data when closing the port; this can cause some
+ * stupid devices that don't respond to URBs on a particular port to hang
+ * for 30 seconds when probin fails.
+ */
+ if (ioctl (priv->fd, TIOCGSERIAL, &sinfo) == 0) {
+ sinfo.closing_wait = ASYNC_CLOSING_WAIT_NONE;
+ ioctl (priv->fd, TIOCSSERIAL, &sinfo);
+ }
+
priv->channel = g_io_channel_unix_new (priv->fd);
g_io_channel_set_encoding (priv->channel, NULL, NULL);
priv->watch_id = g_io_add_watch (priv->channel,
@@ -745,13 +761,7 @@ mm_serial_port_open (MMSerialPort *self, GError **error)
success:
priv->open_count++;
- if (mm_options_debug ()) {
- GTimeVal tv;
-
- g_get_current_time (&tv);
- g_debug ("<%ld.%ld> (%s) device open count is %d (open)",
- tv.tv_sec, tv.tv_usec, device, priv->open_count);
- }
+ mm_dbg ("(%s) device open count is %d (open)", device, priv->open_count);
return TRUE;
error:
@@ -785,13 +795,7 @@ mm_serial_port_close (MMSerialPort *self)
priv->open_count--;
- if (mm_options_debug ()) {
- GTimeVal tv;
-
- g_get_current_time (&tv);
- g_debug ("<%ld.%ld> (%s) device open count is %d (close)",
- tv.tv_sec, tv.tv_usec, device, priv->open_count);
- }
+ mm_dbg ("(%s) device open count is %d (close)", device, priv->open_count);
if (priv->open_count > 0)
return;
@@ -802,7 +806,9 @@ mm_serial_port_close (MMSerialPort *self)
}
if (priv->fd >= 0) {
- g_message ("(%s) closing serial device...", device);
+ GTimeVal tv_start, tv_end;
+
+ mm_info ("(%s) closing serial port...", device);
mm_port_set_connected (MM_PORT (self), FALSE);
@@ -816,9 +822,24 @@ mm_serial_port_close (MMSerialPort *self)
mm_serial_port_flash_cancel (self);
+ g_get_current_time (&tv_start);
+
tcsetattr (priv->fd, TCSANOW, &priv->old_t);
+ tcflush (priv->fd, TCIOFLUSH);
close (priv->fd);
priv->fd = -1;
+
+ g_get_current_time (&tv_end);
+
+ mm_info ("(%s) serial port closed", device);
+
+ /* Some ports don't respond to data and when close is called
+ * the serial layer waits up to 30 second (closing_wait) for
+ * that data to send before giving up and returning from close().
+ * Log that. See GNOME bug #630670 for more details.
+ */
+ if (tv_end.tv_sec - tv_start.tv_sec > 20)
+ mm_warn ("(%s): close blocked by driver for more than 20 seconds!", device);
}
/* Clear the command queue */
@@ -1185,6 +1206,9 @@ set_property (GObject *object, guint prop_id,
MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (object);
switch (prop_id) {
+ case PROP_FD:
+ priv->fd = g_value_get_int (value);
+ break;
case PROP_BAUD:
priv->baud = g_value_get_uint (value);
break;
@@ -1213,6 +1237,9 @@ get_property (GObject *object, guint prop_id,
MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (object);
switch (prop_id) {
+ case PROP_FD:
+ g_value_set_int (value, priv->fd);
+ break;
case PROP_BAUD:
g_value_set_uint (value, priv->baud);
break;
@@ -1276,6 +1303,14 @@ mm_serial_port_class_init (MMSerialPortClass *klass)
/* Properties */
g_object_class_install_property
+ (object_class, PROP_FD,
+ g_param_spec_int (MM_SERIAL_PORT_FD,
+ "File descriptor",
+ "Fiel descriptor",
+ -1, G_MAXINT, -1,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property
(object_class, PROP_BAUD,
g_param_spec_uint (MM_SERIAL_PORT_BAUD,
"Baud",
diff --git a/src/mm-serial-port.h b/src/mm-serial-port.h
index f78f793..5fee1b4 100644
--- a/src/mm-serial-port.h
+++ b/src/mm-serial-port.h
@@ -35,6 +35,7 @@
#define MM_SERIAL_PORT_PARITY "parity"
#define MM_SERIAL_PORT_STOPBITS "stopbits"
#define MM_SERIAL_PORT_SEND_DELAY "send-delay"
+#define MM_SERIAL_PORT_FD "fd" /* Construct-only */
typedef struct _MMSerialPort MMSerialPort;
typedef struct _MMSerialPortClass MMSerialPortClass;
diff --git a/src/mm-utils.c b/src/mm-utils.c
index 56182c0..c435d1d 100644
--- a/src/mm-utils.c
+++ b/src/mm-utils.c
@@ -76,3 +76,17 @@ utils_hexstr2bin (const char *hex, gsize *out_len)
/* End from hostap */
+char *
+utils_bin2hexstr (const guint8 *bin, gsize len)
+{
+ GString *ret;
+ gsize i;
+
+ g_return_val_if_fail (bin != NULL, NULL);
+
+ ret = g_string_sized_new (len * 2 + 1);
+ for (i = 0; i < len; i++)
+ g_string_append_printf (ret, "%.2X", bin[i]);
+ return g_string_free (ret, FALSE);
+}
+
diff --git a/src/mm-utils.h b/src/mm-utils.h
index 79e7827..1b9b328 100644
--- a/src/mm-utils.h
+++ b/src/mm-utils.h
@@ -20,5 +20,7 @@ int utils_hex2byte (const char *hex);
char *utils_hexstr2bin (const char *hex, gsize *out_len);
+char *utils_bin2hexstr (const guint8 *bin, gsize len);
+
#endif /* MM_UTILS_H */
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index 74255db..e265bc1 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -1,7 +1,10 @@
INCLUDES = \
-I$(top_srcdir)/src
-noinst_PROGRAMS = test-modem-helpers
+noinst_PROGRAMS = \
+ test-modem-helpers \
+ test-charsets \
+ test-qcdm-serial-port
test_modem_helpers_SOURCES = \
test-modem-helpers.c
@@ -13,10 +16,36 @@ test_modem_helpers_LDADD = \
$(top_builddir)/src/libmodem-helpers.la \
$(MM_LIBS)
+test_charsets_SOURCES = \
+ test-charsets.c
+
+test_charsets_CPPFLAGS = \
+ $(MM_CFLAGS)
+
+test_charsets_LDADD = \
+ $(top_builddir)/src/libmodem-helpers.la \
+ $(MM_LIBS)
+
+test_qcdm_serial_port_SOURCES = \
+ test-qcdm-serial-port.c
+
+test_qcdm_serial_port_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ -I$(top_srcdir)
+
+test_qcdm_serial_port_LDADD = \
+ $(MM_LIBS) \
+ $(top_builddir)/src/libserial.la \
+ $(top_builddir)/src/libmodem-helpers.la \
+ $(top_builddir)/libqcdm/src/libqcdm.la \
+ -lutil
+
if WITH_TESTS
check-local: test-modem-helpers
$(abs_builddir)/test-modem-helpers
+ $(abs_builddir)/test-charsets
+ $(abs_builddir)/test-qcdm-serial-port
endif
diff --git a/src/tests/test-charsets.c b/src/tests/test-charsets.c
new file mode 100644
index 0000000..656b80c
--- /dev/null
+++ b/src/tests/test-charsets.c
@@ -0,0 +1,323 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ */
+
+#include <glib.h>
+#include <string.h>
+
+#include "mm-modem-helpers.h"
+
+static void
+test_def_chars (void *f, gpointer d)
+{
+ /* Test that a string with all the characters in the GSM 03.38 charset
+ * are converted from UTF-8 to GSM and back to UTF-8 successfully.
+ */
+ static const char *s = "@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà";
+ guint8 *gsm, *utf8;
+ guint32 len = 0;
+
+ /* Convert to GSM */
+ gsm = mm_charset_utf8_to_unpacked_gsm (s, &len);
+ g_assert (gsm);
+ g_assert_cmpint (len, ==, 127);
+
+ /* And back to UTF-8 */
+ utf8 = mm_charset_gsm_unpacked_to_utf8 (gsm, len);
+ g_assert (utf8);
+ g_assert_cmpstr (s, ==, (const char *) utf8);
+
+ g_free (gsm);
+ g_free (utf8);
+}
+
+static void
+test_esc_chars (void *f, gpointer d)
+{
+ /* Test that a string with all the characters in the extended GSM 03.38
+ * charset are converted from UTF-8 to GSM and back to UTF-8 successfully.
+ */
+ static const char *s = "\f^{}\\[~]|€";
+ guint8 *gsm, *utf8;
+ guint32 len = 0;
+
+ /* Convert to GSM */
+ gsm = mm_charset_utf8_to_unpacked_gsm (s, &len);
+ g_assert (gsm);
+ g_assert_cmpint (len, ==, 20);
+
+ /* And back to UTF-8 */
+ utf8 = mm_charset_gsm_unpacked_to_utf8 (gsm, len);
+ g_assert (utf8);
+ g_assert_cmpstr (s, ==, (const char *) utf8);
+
+ g_free (gsm);
+ g_free (utf8);
+}
+
+static void
+test_mixed_chars (void *f, gpointer d)
+{
+ /* Test that a string with a mix of GSM 03.38 default and extended characters
+ * is converted from UTF-8 to GSM and back to UTF-8 successfully.
+ */
+ static const char *s = "@£$¥èéùìø\fΩΠΨΣΘ{ΞÆæß(})789\\:;<=>[?¡QRS]TUÖ|Ñܧ¿abpqrstuvöñüà€";
+ guint8 *gsm, *utf8;
+ guint32 len = 0;
+
+ /* Convert to GSM */
+ gsm = mm_charset_utf8_to_unpacked_gsm (s, &len);
+ g_assert (gsm);
+ g_assert_cmpint (len, ==, 69);
+
+ /* And back to UTF-8 */
+ utf8 = mm_charset_gsm_unpacked_to_utf8 (gsm, len);
+ g_assert (utf8);
+ g_assert_cmpstr (s, ==, (const char *) utf8);
+
+ g_free (gsm);
+ g_free (utf8);
+}
+
+static void
+test_unpack_gsm7 (void *f, gpointer d)
+{
+ static const guint8 gsm[] = { 0xC8, 0xF7, 0x1D, 0x14, 0x96, 0x97, 0x41, 0xF9, 0x77, 0xFD, 0x07 };
+ static const guint8 expected[] = { 0x48, 0x6f, 0x77, 0x20, 0x61, 0x72, 0x65, 0x20, 0x79, 0x6f, 0x75, 0x3f };
+ guint8 *unpacked;
+ guint32 unpacked_len = 0;
+
+ unpacked = gsm_unpack (gsm, sizeof (gsm), 0, &unpacked_len);
+ g_assert (unpacked);
+ g_assert_cmpint (unpacked_len, ==, sizeof (expected));
+ g_assert_cmpint (memcmp (unpacked, expected, unpacked_len), ==, 0);
+
+ g_free (unpacked);
+}
+
+static void
+test_unpack_gsm7_7_chars (void *f, gpointer d)
+{
+ static const guint8 gsm[] = { 0xF1, 0x7B, 0x59, 0x4E, 0xCF, 0xD7, 0x01 };
+ static const guint8 expected[] = { 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x00 };
+ guint8 *unpacked;
+ guint32 unpacked_len = 0;
+
+ /* Tests the edge case where there are 7 bits left in the packed
+ * buffer but those 7 bits do not contain a character. In this case
+ * we expect a trailing NULL byte and the caller must know enough about
+ * the intended message to remove it when required.
+ */
+
+ unpacked = gsm_unpack (gsm, sizeof (gsm), 0, &unpacked_len);
+ g_assert (unpacked);
+ g_assert_cmpint (unpacked_len, ==, sizeof (expected));
+ g_assert_cmpint (memcmp (unpacked, expected, unpacked_len), ==, 0);
+
+ g_free (unpacked);
+}
+
+static void
+test_unpack_gsm7_all_chars (void *f, gpointer d)
+{
+ /* Packed array of all chars in GSM default and extended charset */
+ static const guint8 gsm[] = {
+ 0x80, 0x80, 0x60, 0x40, 0x28, 0x18, 0x0E, 0x88, 0x84, 0x62, 0xC1, 0x68,
+ 0x38, 0x1E, 0x90, 0x88, 0x64, 0x42, 0xA9, 0x58, 0x2E, 0x98, 0x8C, 0x66,
+ 0xC3, 0xE9, 0x78, 0x3E, 0xA0, 0x90, 0x68, 0x44, 0x2A, 0x99, 0x4E, 0xA8,
+ 0x94, 0x6A, 0xC5, 0x6A, 0xB9, 0x5E, 0xB0, 0x98, 0x6C, 0x46, 0xAB, 0xD9,
+ 0x6E, 0xB8, 0x9C, 0x6E, 0xC7, 0xEB, 0xF9, 0x7E, 0xC0, 0xA0, 0x70, 0x48,
+ 0x2C, 0x1A, 0x8F, 0xC8, 0xA4, 0x72, 0xC9, 0x6C, 0x3A, 0x9F, 0xD0, 0xA8,
+ 0x74, 0x4A, 0xAD, 0x5A, 0xAF, 0xD8, 0xAC, 0x76, 0xCB, 0xED, 0x7A, 0xBF,
+ 0xE0, 0xB0, 0x78, 0x4C, 0x2E, 0x9B, 0xCF, 0xE8, 0xB4, 0x7A, 0xCD, 0x6E,
+ 0xBB, 0xDF, 0xF0, 0xB8, 0x7C, 0x4E, 0xAF, 0xDB, 0xEF, 0xF8, 0xBC, 0x7E,
+ 0xCF, 0xEF, 0xFB, 0xFF, 0x1B, 0xC5, 0x86, 0xB2, 0x41, 0x6D, 0x52, 0x9B,
+ 0xD7, 0x86, 0xB7, 0xE9, 0x6D, 0x7C, 0x1B, 0xE0, 0xA6, 0x0C
+ };
+ static const guint8 ext[] = {
+ 0x1B, 0x0A, 0x1B, 0x14, 0x1B, 0x28, 0x1B, 0x29, 0x1B, 0x2F, 0x1B, 0x3C,
+ 0x1B, 0x3D, 0x1B, 0x3E, 0x1B, 0x40, 0x1B, 0x65
+ };
+ guint8 *unpacked;
+ guint32 unpacked_len = 0;
+ int i;
+
+ unpacked = gsm_unpack (gsm, sizeof (gsm), 0, &unpacked_len);
+ g_assert (unpacked);
+ g_assert_cmpint (unpacked_len, ==, 148);
+
+ /* Test default chars */
+ for (i = 0; i < 128; i++)
+ g_assert_cmpint (unpacked[i], ==, i);
+
+ /* Text extended chars */
+ g_assert_cmpint (memcmp ((guint8 *) (unpacked + 128), &ext[0], sizeof (ext)), ==, 0);
+
+ g_free (unpacked);
+}
+
+static void
+test_pack_gsm7 (void *f, gpointer d)
+{
+ static const guint8 unpacked[] = { 0x48, 0x6f, 0x77, 0x20, 0x61, 0x72, 0x65, 0x20, 0x79, 0x6f, 0x75, 0x3f };
+ static const guint8 expected[] = { 0xC8, 0xF7, 0x1D, 0x14, 0x96, 0x97, 0x41, 0xF9, 0x77, 0xFD, 0x07 };
+ guint8 *packed;
+ guint32 packed_len = 0;
+
+ packed = gsm_pack (unpacked, sizeof (unpacked), 0, &packed_len);
+ g_assert (packed);
+ g_assert_cmpint (packed_len, ==, sizeof (expected));
+ g_assert_cmpint (memcmp (packed, expected, packed_len), ==, 0);
+
+ g_free (packed);
+}
+
+static void
+test_pack_gsm7_7_chars (void *f, gpointer d)
+{
+ static const guint8 unpacked[] = { 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75 };
+ static const guint8 expected[] = { 0xF1, 0x7B, 0x59, 0x4E, 0xCF, 0xD7, 0x01 };
+ guint8 *packed;
+ guint32 packed_len = 0;
+
+ /* Tests the edge case where there are 7 bits left in the packed
+ * buffer but those 7 bits do not contain a character. In this case
+ * we expect a trailing NULL byte and the caller must know enough about
+ * the intended message to remove it when required.
+ */
+
+ packed = gsm_pack (unpacked, sizeof (unpacked), 0, &packed_len);
+ g_assert (packed);
+ g_assert_cmpint (packed_len, ==, sizeof (expected));
+ g_assert_cmpint (memcmp (packed, expected, packed_len), ==, 0);
+
+ g_free (packed);
+}
+
+#if 0
+static void
+print_array (const guint8 *array, guint32 len)
+{
+ int col;
+ guint8 c;
+
+ g_print ("\n");
+ for (c = 0, col = 0; c < len; c++) {
+ g_print ("0x%02X, ", array[c] & 0xFF);
+ if (col++ == 11) {
+ col = 0;
+ g_print ("\n");
+ }
+ }
+ g_print ("\n");
+}
+#endif
+
+static void
+test_pack_gsm7_all_chars (void *f, gpointer d)
+{
+ /* Packed array of all chars in GSM default and extended charset */
+ static const guint8 expected[] = {
+ 0x80, 0x80, 0x60, 0x40, 0x28, 0x18, 0x0E, 0x88, 0x84, 0x62, 0xC1, 0x68,
+ 0x38, 0x1E, 0x90, 0x88, 0x64, 0x42, 0xA9, 0x58, 0x2E, 0x98, 0x8C, 0x66,
+ 0xC3, 0xE9, 0x78, 0x3E, 0xA0, 0x90, 0x68, 0x44, 0x2A, 0x99, 0x4E, 0xA8,
+ 0x94, 0x6A, 0xC5, 0x6A, 0xB9, 0x5E, 0xB0, 0x98, 0x6C, 0x46, 0xAB, 0xD9,
+ 0x6E, 0xB8, 0x9C, 0x6E, 0xC7, 0xEB, 0xF9, 0x7E, 0xC0, 0xA0, 0x70, 0x48,
+ 0x2C, 0x1A, 0x8F, 0xC8, 0xA4, 0x72, 0xC9, 0x6C, 0x3A, 0x9F, 0xD0, 0xA8,
+ 0x74, 0x4A, 0xAD, 0x5A, 0xAF, 0xD8, 0xAC, 0x76, 0xCB, 0xED, 0x7A, 0xBF,
+ 0xE0, 0xB0, 0x78, 0x4C, 0x2E, 0x9B, 0xCF, 0xE8, 0xB4, 0x7A, 0xCD, 0x6E,
+ 0xBB, 0xDF, 0xF0, 0xB8, 0x7C, 0x4E, 0xAF, 0xDB, 0xEF, 0xF8, 0xBC, 0x7E,
+ 0xCF, 0xEF, 0xFB, 0xFF, 0x1B, 0xC5, 0x86, 0xB2, 0x41, 0x6D, 0x52, 0x9B,
+ 0xD7, 0x86, 0xB7, 0xE9, 0x6D, 0x7C, 0x1B, 0xE0, 0xA6, 0x0C
+ };
+ static const guint8 ext[] = {
+ 0x1B, 0x0A, 0x1B, 0x14, 0x1B, 0x28, 0x1B, 0x29, 0x1B, 0x2F, 0x1B, 0x3C,
+ 0x1B, 0x3D, 0x1B, 0x3E, 0x1B, 0x40, 0x1B, 0x65
+ };
+ guint8 *packed, c;
+ guint32 packed_len = 0;
+ GByteArray *unpacked;
+
+ unpacked = g_byte_array_sized_new (148);
+ for (c = 0; c < 128; c++)
+ g_byte_array_append (unpacked, &c, 1);
+ for (c = 0; c < sizeof (ext); c++)
+ g_byte_array_append (unpacked, &ext[c], 1);
+
+ packed = gsm_pack (unpacked->data, unpacked->len, 0, &packed_len);
+ g_assert (packed);
+ g_assert_cmpint (packed_len, ==, sizeof (expected));
+ g_assert_cmpint (memcmp (packed, expected, packed_len), ==, 0);
+
+ g_free (packed);
+ g_byte_array_free (unpacked, TRUE);
+}
+
+static void
+test_pack_gsm7_24_chars (void *f, gpointer d)
+{
+ static const guint8 unpacked[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
+ };
+ guint8 *packed;
+ guint32 packed_len = 0;
+
+ /* Tests that no empty trailing byte is added when all the 7-bit characters
+ * are packed into an exact number of bytes.
+ */
+
+ packed = gsm_pack (unpacked, sizeof (unpacked), 0, &packed_len);
+ g_assert (packed);
+ g_assert_cmpint (packed_len, ==, 21);
+
+ g_free (packed);
+}
+
+
+#if GLIB_CHECK_VERSION(2,25,12)
+typedef GTestFixtureFunc TCFunc;
+#else
+typedef void (*TCFunc)(void);
+#endif
+
+#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL)
+
+int main (int argc, char **argv)
+{
+ GTestSuite *suite;
+ gint result;
+
+ g_test_init (&argc, &argv, NULL);
+
+ suite = g_test_get_root ();
+
+ g_test_suite_add (suite, TESTCASE (test_def_chars, NULL));
+ g_test_suite_add (suite, TESTCASE (test_esc_chars, NULL));
+ g_test_suite_add (suite, TESTCASE (test_mixed_chars, NULL));
+
+ g_test_suite_add (suite, TESTCASE (test_unpack_gsm7, NULL));
+ g_test_suite_add (suite, TESTCASE (test_unpack_gsm7_7_chars, NULL));
+ g_test_suite_add (suite, TESTCASE (test_unpack_gsm7_all_chars, NULL));
+
+ g_test_suite_add (suite, TESTCASE (test_pack_gsm7, NULL));
+ g_test_suite_add (suite, TESTCASE (test_pack_gsm7_7_chars, NULL));
+ g_test_suite_add (suite, TESTCASE (test_pack_gsm7_all_chars, NULL));
+ g_test_suite_add (suite, TESTCASE (test_pack_gsm7_24_chars, NULL));
+
+ result = g_test_run ();
+
+ return result;
+}
+
diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c
index 92a7af8..946916f 100644
--- a/src/tests/test-modem-helpers.c
+++ b/src/tests/test-modem-helpers.c
@@ -17,6 +17,7 @@
#include <string.h>
#include "mm-modem-helpers.h"
+#include "mm-log.h"
typedef struct {
GPtrArray *solicited_creg;
@@ -711,6 +712,27 @@ test_creg_cgreg_multi2_unsolicited (void *f, gpointer d)
}
static void
+test_cgreg2_x220_unsolicited (void *f, gpointer d)
+{
+ TestData *data = (TestData *) d;
+ const char *reply = "\r\n+CGREG: 2,1, 81ED, 1A9CEB\r\n";
+ const CregResult result = { 1, 0x81ED, 0x1A9CEB, -1, 4, TRUE};
+
+ /* Tests random spaces in response */
+ test_creg_match ("Alcatel One-Touch X220D CGREG=2", FALSE, reply, data, &result);
+}
+
+static void
+test_creg2_s8500_wave_unsolicited (void *f, gpointer d)
+{
+ TestData *data = (TestData *) d;
+ const char *reply = "\r\n+CREG: 2,1,000B,2816, B, C2816\r\n";
+ const CregResult result = { 1, 0x000B, 0x2816, 0, 7, FALSE};
+
+ test_creg_match ("Samsung Wave S8500 CREG=2", FALSE, reply, data, &result);
+}
+
+static void
test_cscs_icon225_support_response (void *f, gpointer d)
{
const char *reply = "\r\n+CSCS: (\"IRA\",\"GSM\",\"UCS2\")\r\n";
@@ -771,6 +793,372 @@ test_cscs_blackberry_support_response (void *f, gpointer d)
g_assert (charsets == MM_MODEM_CHARSET_IRA);
}
+typedef struct {
+ char *devid;
+ char *desc;
+ guint vid;
+ guint pid;
+ const char *ati;
+ const char *ati1;
+ const char *gsn;
+ const char *revision;
+ const char *model;
+ const char *manf;
+} DevidItem;
+
+static DevidItem devids[] = {
+ { "36e7a8e78637fd380b2664507ea5de8fc317d05b",
+ "Huawei E1550",
+ 0x12d1, 0x1001,
+ "\nManufacturer: huawei\n"
+ "Model: E1550\n"
+ "Revision: 11.608.09.01.21\n"
+ "IMEI: 235012412595195\n"
+ "+GCAP: +CGSM,+FCLASS,+DS\n",
+ NULL,
+ "\n235012412595195\n",
+ "\n11.608.09.01.21\n",
+ "\nE1550\n",
+ "\nhuawei\n"
+ },
+ { "33b0fc4a06af5448df656ce12925979acf1cb600",
+ "Huawei EC121",
+ 0x12d1, 0x1411,
+ "\nManufacturer: HUAWEI INCORPORATED\n"
+ "Model: EC121\n"
+ "Revision: 11.100.17.00.114\n"
+ "ESN: +GSN:12de4fa6\n"
+ "+CIS707-A, +MS, +ES, +DS, +FCLASS\n",
+ NULL,
+ "\n12de4fa6\n",
+ "\n11.100.17.00.114\n",
+ "\nEC121\n",
+ "\nHUAWEI INCORPORATED\n"
+ },
+ { "d17f016a402354eaa1e24855f4308fafca9cadb1",
+ "Sierra USBConnect Mercury",
+ 0x1199, 0x6880,
+ "\nManufacturer: Sierra Wireless, Inc.\n"
+ "Model: C885\n"
+ "Revision: J1_0_1_26AP C:/WS/FW/J1_0_1_26AP/MSM7200A/SRC/AMSS 2009/01/30 07:58:06\n"
+ "IMEI: 987866969112306\n"
+ "IMEI SV: 6\n"
+ "FSN: D603478104511\n"
+ "3GPP Release 6\n"
+ "+GCAP: +CGSM,+DS,+ES\n",
+ NULL,
+ "\n987866969112306\n",
+ "\nJ1_0_1_26AP C:/WS/FW/J1_0_1_26AP/MSM7200A/SRC/AMSS 2009/01/30 07:58:06\n",
+ "\nC885\n",
+ "\nSierra Wireless, Inc.\n"
+ },
+ { "345e9eaad7624393aca85cde9bd859edf462414c",
+ "ZTE MF627",
+ 0x19d2, 0x0031,
+ "\nManufacturer: ZTE INCORPORATED\n"
+ "Model: MF627\n"
+ "Revision: BD_3GHAP673A4V1.0.0B02\n"
+ "IMEI: 023589923858188\n"
+ "+GCAP: +CGSM,+FCLASS,+DS\n",
+ NULL,
+ "\n023589923858188\n",
+ "\nBD_3GHAP673A4V1.0.0B02\n",
+ "\nMF627\n",
+ "\nZTE INCORPORATED\n"
+ },
+ { "69fa133a668b6f4dbf39b73500fd153ec240c73f",
+ "Sony-Ericsson MD300",
+ 0x0fce, 0xd0cf,
+ "\nMD300\n",
+ "\nR3A018\n",
+ "\n349583712939483\n",
+ "\nR3A018\n",
+ "\nMD300\n",
+ "\nSony Ericsson\n"
+ },
+ { "3dad89ed7d774938c38188cf29cf1c211e9d360b",
+ "Option iCON 7.2",
+ 0x0af0, 0x6901,
+ "\nManufacturer: Option N.V.\n"
+ "Model: GTM378\n"
+ "Revision: 2.5.21Hd (Date: Jun 17 2008, Time: 12:30:47)\n",
+ NULL,
+ "\n129512359199159,SE393939TS\n",
+ "\n2.5.21Hd (Date: Jun 17 2008, Time: 12:30:47)\n",
+ "\nGTM378\n",
+ "\nOption N.V.\n"
+ },
+ { "b0acccb956c9eaf2076e03697e74bf998dc44179",
+ "ZTE MF622",
+ 0x19d2, 0x0001,
+ NULL,
+ NULL,
+ "\n235251122555115\n",
+ "\n3UKP671M3V1.0.0B08 3UKP671M3V1.0.0B08 1 [Jan 07 2008 16:00:00]\n",
+ "\nMF622\n",
+ "\nZTE INCORPORATED\n"
+ },
+ { "29a5b258f1dc6f50c66a1a9a1ecdde97560799ab",
+ "Option 452",
+ 0x0af0, 0x7901,
+ "\nManufacturer: Option N.V.\n"
+ "Model: GlobeTrotter HSUPA Modem\n"
+ "Revision: 2.12.0.0Hd (Date: Oct 29 2009, Time: 09:56:48)\n",
+ "\nManufacturer: Option N.V.\n"
+ "Model: GlobeTrotter HSUPA Modem\n"
+ "Revision: 2.12.0.0Hd (Date: Oct 29 2009, Time: 09:56:48)\n",
+ "\n000125491259519,PH2155R3TR\n",
+ "\n2.12.0.0Hd (Date: Oct 29 2009, Time: 09:56:48)\n",
+ "\nGlobeTrotter HSUPA Modem\n",
+ "\nOption N.V.\n"
+ },
+ { "c756c67e960e693d5d221e381ea170b60bb9288f",
+ "Novatel XU870",
+ 0x413c, 0x8118,
+ "\nManufacturer: Novatel Wireless Incorporated\n"
+ "Model: DELL XU870 ExpressCard\n"
+ "Revision: 9.5.05.01-02 [2006-10-20 17:19:09]\n"
+ "IMEI: 012051505051501\n"
+ "+GCAP: +CGSM,+DS\n",
+ "\nManufacturer: Novatel Wireless Incorporated\n"
+ "Model: DELL XU870 ExpressCard\n"
+ "Revision: 9.5.05.01-02 [2006-10-20 17:19:09]\n"
+ "IMEI: 012051505051501\n"
+ "+GCAP: +CGSM,+DS\n",
+ "\n012051505051501\n",
+ "\n9.5.05.01-02 [2006-10-20 17:19:09]\n",
+ "\nDELL XU870 ExpressCard\n",
+ "\nNovatel Wireless Incorporated\n"
+ },
+ { "4162ba918ab54b7776bccc3830e6c6b7a6738244",
+ "Zoom 4596",
+ 0x1c9e, 0x9603,
+ "\nManufacturer: Manufacturer\n"
+ "Model: HSPA USB MODEM\n"
+ "Revision: LQA0021.1.1_M573A\n"
+ "IMEI: 239664699635121\n"
+ "+GCAP: +CGSM,+FCLASS,+DS\n",
+ "\nManufacturer: Manufacturer\n"
+ "Model: HSPA USB MODEM\n"
+ "Revision: LQA0021.1.1_M573A\n"
+ "IMEI: 239664699635121\n"
+ "+GCAP: +CGSM,+FCLASS,+DS\n",
+ "\n239664699635121\n",
+ "\nLQA0021.1.1_M573A\n",
+ "\nHSPA USB MODEM\n",
+ "\nManufacturer\n"
+ },
+ { "6d3a2fccd3588943a8962fd1e0d3ba752c706660",
+ "C-MOTECH CDX-650",
+ 0x16d8, 0x6512,
+ "\nManufacturer: C-MOTECH Co., Ltd.\r\r\n"
+ "Model: CDX-650 \r\r\n"
+ "Revision: CDX65UAC03\r\r\n"
+ "Esn: 3B0C4B98\r\r\n"
+ "+GCAP: +CIS707A, +MS, +ES, +DS, +FCLASS\r\n",
+ "\nManufacturer: C-MOTECH Co., Ltd.\r\r\n"
+ "Model: CDX-650 \r\r\n"
+ "Revision: CDX65UAC03\r\r\n"
+ "Esn: 3B0C4B98\r\r\n"
+ "+GCAP: +CIS707A, +MS, +ES, +DS, +FCLASS\r\n",
+ "\n0x3B0C4B98\n",
+ "\nCDX65UAC03 1 [Oct 17 2007 13:30:00]\n",
+ "\nModel CDX-650 \n",
+ "\nC-MOTECH Co., Ltd.\n"
+ },
+ { "cf50da63e6d48beb1d1c3b41d70ef6fa534c3e13",
+ "BUSlink SCWi275u",
+ 0x22b8, 0x3802,
+ "\n144\n",
+ "\n000\n",
+ NULL,
+ "\n\"ADE_05_00_06032300I\"\n",
+ "\n\"GSM900\",\"GSM1800\",\"GSM1900\",\"GSM850\",\"MODEL=I250-000\"\n",
+ "\n\"Motorola CE, Copyright 2000\"\n"
+ },
+ { "2aff568f2b60f3d6f3f6cac708ed5dce77b12b96",
+ "Motorola ROKR E2",
+ 0x22b8, 0x3802,
+ NULL,
+ NULL,
+ "\n\"626936926396996\"\n",
+ "\n\"R564_G_12.00.47P\"\n",
+ "\n\"E2\"\n",
+ "\n\"Motorola\"\n"
+ },
+ { "a7136c6067a43f055ca093cee75cb98ce6c9658e",
+ "Sony-Ericsson W580i",
+ 0x0fce, 0xd089,
+ "\nSony Ericsson W580\n",
+ "\nCXC1123481\n",
+ "\n012505051512505\n",
+ "\nR8BE001 080115 1451 CXC1123481_NAM_1_LA\n",
+ "\nAAC-1052042-BV\n",
+ "\nSony Ericsson\n"
+ },
+ { "b80ee70214bdf9672f2a268ce165ecfd9def5721",
+ "Huawei E226",
+ 0x12d1, 0x1003,
+ "\nManufacturer: huawei\n"
+ "Model: E226\n"
+ "Revision: 11.310.15.00.150\n"
+ "IMEI: 232363662362362\n"
+ "+GCAP: +CGSM,+FCLASS,+DS\n",
+ "\nManufacturer: huawei\n"
+ "Model: E226\n"
+ "Revision: 11.310.15.00.150\n"
+ "IMEI: 232363662362362\n"
+ "+GCAP: +CGSM,+FCLASS,+DS\n",
+ "\n232363662362362\n",
+ "\n11.310.15.00.150\n",
+ "\nE226\n",
+ "\nhuawei\n"
+ },
+ { "d902e1f234863aa107bfc2d0faefbee5ed6901f1",
+ "LG LX265",
+ 0x1004, 0x6000,
+ "\nManufacturer: +GMI: LG Electronics Inc.\n"
+ "Model: +GMI: LG Electronics Inc.+GMM: Model:LG-LX265\n"
+ "Revision: +GMR: LX265V05, 50571\n"
+ "ESN: +GSN: 0x9235EB52\n"
+ "+GCAP: +CIS707-A, +MS, +ES, +DS, +FCLASS\n",
+ "\nManufacturer: +GMI: LG Electronics Inc.\n"
+ "Model: +GMI: LG Electronics Inc.+GMM: Model:LG-LX265\n"
+ "Revision: +GMR: LX265V05, 50571\n"
+ "ESN: +GSN: 0x9235EB52\n"
+ "+GCAP: +CIS707-A, +MS, +ES, +DS, +FCLASS\n",
+ "\n0x9235EB52\n",
+ "\nLX265V05, 50571\n",
+ "\nModel:LG-LX265\n",
+ "\nLG Electronics Inc.\n"
+ },
+ { "543c2920e450e20a46368861fdec3a3b97ba8663",
+ "Nokia 2720a BT",
+ 0x0000, 0x0000,
+ "\nNokia\n",
+ "\n012350150101501\n",
+ "\n012350150101501\n",
+ "\nV 08.62\n"
+ "24-07-09\n"
+ "RM-520\n"
+ "(c) Nokia \n",
+ "\nNokia 2720a-2b\n",
+ "\nNokia\n"
+ },
+ { "6386ffa7a39ced3c9bfd1d693b90975661e54a86",
+ "Gobi 1000",
+ 0x03f0, 0x1f1d,
+ "\nManufacturer: QUALCOMM INCORPORATED\n"
+ "Model: 88\n"
+ "Revision: D1020-SUUAASFA-4352 1 [Apr 14 2008 18:00:00]\n"
+ "IMEI: 239639269236269\n"
+ "+GCAP: +CGSM,+DS\n",
+ "\nManufacturer: QUALCOMM INCORPORATED\n"
+ "Model: 88\n"
+ "Revision: D1020-SUUAASFA-4352 1 [Apr 14 2008 18:00:00]\n"
+ "IMEI: 239639269236269\n"
+ "+GCAP: +CGSM,+DS\n",
+ "\n239639269236269\n",
+ "\nD1020-SUUAASFA-4352 1 [Apr 14 2008 18:00:00]\n",
+ "\n88\n",
+ "\nQUALCOMM INCORPORATED\n"
+ },
+ { NULL }
+};
+
+static void
+test_devid_item (void *f, gpointer d)
+{
+ DevidItem *item = (DevidItem *) d;
+ char *devid;
+
+ g_print ("%s... ", item->desc);
+ devid = mm_create_device_identifier (item->vid,
+ item->pid,
+ item->ati,
+ item->ati1,
+ item->gsn,
+ item->revision,
+ item->model,
+ item->manf);
+ g_assert (devid);
+ if (strcmp (devid, item->devid))
+ g_message ("%s", devid);
+ g_assert (!strcmp (devid, item->devid));
+}
+
+typedef struct {
+ const char *desc;
+ const gint min;
+ const gint max;
+} CindEntry;
+
+static void
+test_cind_results (const char *desc,
+ const char *reply,
+ CindEntry *expected_results,
+ guint32 expected_results_len)
+{
+ guint i;
+ GError *error = NULL;
+ GHashTable *results;
+
+ g_print ("\nTesting %s +CIND response...\n", desc);
+
+ results = mm_parse_cind_test_response (reply, &error);
+ g_assert (results);
+ g_assert (error == NULL);
+
+ g_assert (g_hash_table_size (results) == expected_results_len);
+
+ for (i = 0; i < expected_results_len; i++) {
+ CindEntry *expected = &expected_results[i];
+ CindResponse *compare;
+
+ compare = g_hash_table_lookup (results, expected->desc);
+ g_assert (compare);
+ g_assert_cmpint (i + 1, ==, cind_response_get_index (compare));
+ g_assert_cmpint (expected->min, ==, cind_response_get_min (compare));
+ g_assert_cmpint (expected->max, ==, cind_response_get_max (compare));
+ }
+
+ g_hash_table_destroy (results);
+}
+
+static void
+test_cind_response_linktop_lw273 (void *f, gpointer d)
+{
+ const char *reply = "+CIND: (\"battchg\",(0-5)),(\"signal\",(0-5)),(\"batterywarning\",(0-1)),(\"chargerconnected\",(0-1)),(\"service\",(0-1)),(\"sounder\",(0-1)),(\"message\",(0-1)),()";
+ static CindEntry expected[] = {
+ { "battchg", 0, 5 },
+ { "signal", 0, 5 },
+ { "batterywarning", 0, 1 },
+ { "chargerconnected", 0, 1 },
+ { "service", 0, 1 },
+ { "sounder", 0, 1 },
+ { "message", 0, 1 }
+ };
+
+ test_cind_results ("LW273", reply, &expected[0], ARRAY_LEN (expected));
+}
+
+static void
+test_cind_response_moto_v3m (void *f, gpointer d)
+{
+ const char *reply = "+CIND: (\"Voice Mail\",(0,1)),(\"service\",(0,1)),(\"call\",(0,1)),(\"Roam\",(0-2)),(\"signal\",(0-5)),(\"callsetup\",(0-3)),(\"smsfull\",(0,1))";
+ static CindEntry expected[] = {
+ { "voicemail", 0, 1 },
+ { "service", 0, 1 },
+ { "call", 0, 1 },
+ { "roam", 0, 2 },
+ { "signal", 0, 5 },
+ { "callsetup", 0, 3 },
+ { "smsfull", 0, 1 }
+ };
+
+ test_cind_results ("Motorola V3m", reply, &expected[0], ARRAY_LEN (expected));
+}
+
static TestData *
test_data_new (void)
{
@@ -790,8 +1178,21 @@ test_data_free (TestData *data)
g_free (data);
}
+void
+_mm_log (const char *loc,
+ const char *func,
+ guint32 level,
+ const char *fmt,
+ ...)
+{
+ /* Dummy log function */
+}
+#if GLIB_CHECK_VERSION(2,25,12)
+typedef GTestFixtureFunc TCFunc;
+#else
typedef void (*TCFunc)(void);
+#endif
#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL)
@@ -800,6 +1201,7 @@ int main (int argc, char **argv)
GTestSuite *suite;
TestData *data;
gint result;
+ DevidItem *item = &devids[0];
g_test_init (&argc, &argv, NULL);
@@ -848,12 +1250,14 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_creg2_tm506_solicited, data));
g_test_suite_add (suite, TESTCASE (test_creg2_xu870_unsolicited_unregistered, data));
g_test_suite_add (suite, TESTCASE (test_creg2_md400_unsolicited, data));
+ g_test_suite_add (suite, TESTCASE (test_creg2_s8500_wave_unsolicited, data));
g_test_suite_add (suite, TESTCASE (test_cgreg1_solicited, data));
g_test_suite_add (suite, TESTCASE (test_cgreg1_unsolicited, data));
g_test_suite_add (suite, TESTCASE (test_cgreg2_f3607gw_solicited, data));
g_test_suite_add (suite, TESTCASE (test_cgreg2_f3607gw_unsolicited, data));
g_test_suite_add (suite, TESTCASE (test_cgreg2_md400_unsolicited, data));
+ g_test_suite_add (suite, TESTCASE (test_cgreg2_x220_unsolicited, data));
g_test_suite_add (suite, TESTCASE (test_creg_cgreg_multi_unsolicited, data));
g_test_suite_add (suite, TESTCASE (test_creg_cgreg_multi2_unsolicited, data));
@@ -863,6 +1267,14 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_cscs_buslink_support_response, data));
g_test_suite_add (suite, TESTCASE (test_cscs_blackberry_support_response, data));
+ g_test_suite_add (suite, TESTCASE (test_cind_response_linktop_lw273, data));
+ g_test_suite_add (suite, TESTCASE (test_cind_response_moto_v3m, data));
+
+ while (item->devid) {
+ g_test_suite_add (suite, TESTCASE (test_devid_item, (gconstpointer) item));
+ item++;
+ }
+
result = g_test_run ();
test_data_free (data);
diff --git a/src/tests/test-qcdm-serial-port.c b/src/tests/test-qcdm-serial-port.c
new file mode 100644
index 0000000..3aeed6a
--- /dev/null
+++ b/src/tests/test-qcdm-serial-port.c
@@ -0,0 +1,482 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <string.h>
+#include <pty.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#include "mm-errors.h"
+#include "mm-qcdm-serial-port.h"
+#include "libqcdm/src/commands.h"
+#include "libqcdm/src/utils.h"
+#include "libqcdm/src/com.h"
+#include "mm-log.h"
+
+typedef struct {
+ int master;
+ int slave;
+ gboolean valid;
+ pid_t child;
+} TestData;
+
+static gboolean
+wait_for_child (TestData *d, guint32 timeout)
+{
+ GTimeVal start, now;
+ int status, ret;
+
+ g_get_current_time (&start);
+ do {
+ status = 0;
+ ret = waitpid (d->child, &status, WNOHANG);
+ g_get_current_time (&now);
+ if (d->child && (now.tv_sec - start.tv_sec > timeout)) {
+ /* Kill it */
+ if (g_test_verbose ())
+ g_message ("Killing running child process %d", d->child);
+ kill (d->child, SIGKILL);
+ d->child = 0;
+ }
+ if (ret == 0)
+ sleep (1);
+ } while ((ret <= 0) || (!WIFEXITED (status) && !WIFSIGNALED (status)));
+
+ d->child = 0;
+ return (WIFEXITED (status) && WEXITSTATUS (status) == 0) ? TRUE : FALSE;
+}
+
+static void
+print_buf (const char *detail, const char *buf, gsize len)
+{
+ int i = 0;
+ gboolean newline = FALSE;
+
+ g_print ("%s (%zu) ", detail, len);
+ for (i = 0; i < len; i++) {
+ g_print ("0x%02x ", buf[i] & 0xFF);
+ if (((i + 1) % 12) == 0) {
+ g_print ("\n");
+ newline = TRUE;
+ } else
+ newline = FALSE;
+ }
+
+ if (!newline)
+ g_print ("\n");
+}
+
+static void
+server_send_response (int fd, const char *buf, gsize len)
+{
+ int status;
+ gsize i = 0;
+
+ if (g_test_verbose ())
+ print_buf (">>>", buf, len);
+
+ while (i < len) {
+ errno = 0;
+ status = write (fd, &buf[i], 1);
+ g_assert_cmpint (errno, ==, 0);
+ g_assert (status == 1);
+ i++;
+ usleep (1000);
+ }
+}
+
+static gsize
+server_wait_request (int fd, char *buf, gsize len)
+{
+ fd_set in;
+ int result;
+ struct timeval timeout = { 1, 0 };
+ char readbuf[1024];
+ ssize_t bytes_read;
+ int total = 0, retries = 0;
+ gsize decap_len = 0;
+
+ FD_ZERO (&in);
+ FD_SET (fd, &in);
+ result = select (fd + 1, &in, NULL, NULL, &timeout);
+ g_assert (result == 1);
+ g_assert (FD_ISSET (fd, &in));
+
+ do {
+ errno = 0;
+ bytes_read = read (fd, &readbuf[total], 1);
+ if ((bytes_read == 0) || (errno == EAGAIN)) {
+ /* Haven't gotten the async control char yet */
+ if (retries > 20)
+ return 0; /* 2 seconds, give up */
+
+ /* Otherwise wait a bit and try again */
+ usleep (100000);
+ retries++;
+ continue;
+ } else if (bytes_read == 1) {
+ gboolean more = FALSE, success;
+ gsize used = 0;
+
+ total++;
+ decap_len = 0;
+ success = dm_decapsulate_buffer (readbuf, total, buf, len, &decap_len, &used, &more);
+
+ /* Discard used data */
+ if (used > 0) {
+ total -= used;
+ memmove (readbuf, &readbuf[used], total);
+ }
+
+ if (success && !more) {
+ /* Success; we have a packet */
+ break;
+ }
+ } else {
+ /* Some error occurred */
+ g_assert_not_reached ();
+ }
+ } while (total < sizeof (readbuf));
+
+ if (g_test_verbose ()) {
+ print_buf ("<<<", readbuf, total);
+ print_buf ("D<<", buf, decap_len);
+ }
+
+ return decap_len;
+}
+
+typedef void (*VerInfoCb) (MMQcdmSerialPort *port,
+ GByteArray *response,
+ GError *error,
+ gpointer user_data);
+
+static void
+qcdm_verinfo_expect_success_cb (MMQcdmSerialPort *port,
+ GByteArray *response,
+ GError *error,
+ gpointer user_data)
+{
+ GMainLoop *loop = user_data;
+
+ g_assert_no_error (error);
+ g_assert (response->len > 0);
+ g_main_loop_quit (loop);
+}
+
+static void
+qcdm_request_verinfo (MMQcdmSerialPort *port, VerInfoCb cb, GMainLoop *loop)
+{
+ GError *error = NULL;
+ GByteArray *verinfo;
+ gint len;
+
+ /* Build up the probe command */
+ verinfo = g_byte_array_sized_new (50);
+ len = qcdm_cmd_version_info_new ((char *) verinfo->data, 50, &error);
+ if (len <= 0) {
+ g_byte_array_free (verinfo, TRUE);
+ g_assert_no_error (error);
+ }
+ verinfo->len = len;
+
+ mm_qcdm_serial_port_queue_command (port, verinfo, 3, cb, loop);
+}
+
+static void
+qcdm_test_child (int fd, VerInfoCb cb)
+{
+ MMQcdmSerialPort *port;
+ GMainLoop *loop;
+ gboolean success;
+ GError *error = NULL;
+
+ /* In the child */
+ g_type_init ();
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ port = mm_qcdm_serial_port_new_fd (fd, MM_PORT_TYPE_PRIMARY);
+ g_assert (port);
+
+ success = mm_serial_port_open (MM_SERIAL_PORT (port), &error);
+ g_assert_no_error (error);
+ g_assert (success);
+
+ qcdm_request_verinfo (port, cb, loop);
+ g_main_loop_run (loop);
+
+ mm_serial_port_close (MM_SERIAL_PORT (port));
+ g_object_unref (port);
+}
+
+/* Test that a Version Info request/response is processed correctly to
+ * make sure things in general are working.
+ */
+static void
+test_verinfo (void *f)
+{
+ TestData *d = f;
+ char req[512];
+ gsize req_len;
+ pid_t cpid;
+ const char rsp[] = {
+ 0x00, 0x41, 0x75, 0x67, 0x20, 0x31, 0x39, 0x20, 0x32, 0x30, 0x30, 0x38,
+ 0x32, 0x30, 0x3a, 0x34, 0x38, 0x3a, 0x34, 0x37, 0x4f, 0x63, 0x74, 0x20,
+ 0x32, 0x39, 0x20, 0x32, 0x30, 0x30, 0x37, 0x31, 0x39, 0x3a, 0x30, 0x30,
+ 0x3a, 0x30, 0x30, 0x53, 0x43, 0x4e, 0x52, 0x5a, 0x2e, 0x2e, 0x2e, 0x2a,
+ 0x06, 0x04, 0xb9, 0x0b, 0x02, 0x00, 0xb2, 0x19, 0xc4, 0x7e
+ };
+
+ signal (SIGCHLD, SIG_DFL);
+ cpid = fork ();
+ g_assert (cpid >= 0);
+
+ if (cpid == 0) {
+ /* In the child */
+ qcdm_test_child (d->slave, qcdm_verinfo_expect_success_cb);
+ exit (0);
+ }
+ /* Parent */
+ d->child = cpid;
+
+ req_len = server_wait_request (d->master, req, sizeof (req));
+ g_assert (req_len == 1);
+ g_assert_cmpint (req[0], ==, 0x00);
+
+ server_send_response (d->master, rsp, sizeof (rsp));
+ g_assert (wait_for_child (d, 3));
+}
+
+static void
+qcdm_verinfo_expect_fail_cb (MMQcdmSerialPort *port,
+ GByteArray *response,
+ GError *error,
+ gpointer user_data)
+{
+ GMainLoop *loop = user_data;
+
+ g_assert_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL);
+ g_main_loop_quit (loop);
+}
+
+/* Test that a Sierra CnS response to a Version Info command correctly
+ * raises an error in the child's response handler.
+ */
+static void
+test_sierra_cns_rejected (void *f)
+{
+ TestData *d = f;
+ char req[512];
+ gsize req_len;
+ pid_t cpid;
+ const char rsp[] = {
+ 0x7e, 0x00, 0x0a, 0x6b, 0x6d, 0x00, 0x00, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e
+ };
+
+ signal (SIGCHLD, SIG_DFL);
+ cpid = fork ();
+ g_assert (cpid >= 0);
+
+ if (cpid == 0) {
+ /* In the child */
+ qcdm_test_child (d->slave, qcdm_verinfo_expect_fail_cb);
+ exit (0);
+ }
+ /* Parent */
+ d->child = cpid;
+
+ req_len = server_wait_request (d->master, req, sizeof (req));
+ g_assert (req_len == 1);
+ g_assert_cmpint (req[0], ==, 0x00);
+
+ server_send_response (d->master, rsp, sizeof (rsp));
+
+ /* We expect the child to exit normally */
+ g_assert (wait_for_child (d, 3));
+}
+
+/* Test that a random response to a Version Info command correctly
+ * raises an error in the child's response handler.
+ */
+static void
+test_random_data_rejected (void *f)
+{
+ TestData *d = f;
+ char req[512];
+ gsize req_len;
+ pid_t cpid;
+ const char rsp[] = {
+ 0x7e, 0x7e, 0x7e, 0x6b, 0x6d, 0x7e, 0x7e, 0x7e, 0x7e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e
+ };
+
+ signal (SIGCHLD, SIG_DFL);
+ cpid = fork ();
+ g_assert (cpid >= 0);
+
+ if (cpid == 0) {
+ /* In the child */
+ qcdm_test_child (d->slave, qcdm_verinfo_expect_fail_cb);
+ exit (0);
+ }
+ /* Parent */
+ d->child = cpid;
+
+ req_len = server_wait_request (d->master, req, sizeof (req));
+ g_assert (req_len == 1);
+ g_assert_cmpint (req[0], ==, 0x00);
+
+ server_send_response (d->master, rsp, sizeof (rsp));
+
+ /* We expect the child to exit normally */
+ g_assert (wait_for_child (d, 3));
+}
+
+/* Test that a bunch of frame markers at the beginning of a valid response
+ * to a Version Info command is parsed correctly.
+ */
+static void
+test_leading_frame_markers (void *f)
+{
+ TestData *d = f;
+ char req[512];
+ gsize req_len;
+ pid_t cpid;
+ const char rsp[] = {
+ 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e,
+ 0x00, 0x41, 0x75, 0x67, 0x20, 0x31, 0x39, 0x20, 0x32, 0x30, 0x30, 0x38,
+ 0x32, 0x30, 0x3a, 0x34, 0x38, 0x3a, 0x34, 0x37, 0x4f, 0x63, 0x74, 0x20,
+ 0x32, 0x39, 0x20, 0x32, 0x30, 0x30, 0x37, 0x31, 0x39, 0x3a, 0x30, 0x30,
+ 0x3a, 0x30, 0x30, 0x53, 0x43, 0x4e, 0x52, 0x5a, 0x2e, 0x2e, 0x2e, 0x2a,
+ 0x06, 0x04, 0xb9, 0x0b, 0x02, 0x00, 0xb2, 0x19, 0xc4, 0x7e
+ };
+
+ signal (SIGCHLD, SIG_DFL);
+ cpid = fork ();
+ g_assert (cpid >= 0);
+
+ if (cpid == 0) {
+ /* In the child */
+ qcdm_test_child (d->slave, qcdm_verinfo_expect_success_cb);
+ exit (0);
+ }
+ /* Parent */
+ d->child = cpid;
+
+ req_len = server_wait_request (d->master, req, sizeof (req));
+ g_assert (req_len == 1);
+ g_assert_cmpint (req[0], ==, 0x00);
+
+ server_send_response (d->master, rsp, sizeof (rsp));
+
+ /* We expect the child to exit normally */
+ g_assert (wait_for_child (d, 3));
+}
+
+static void
+test_pty_create (gpointer user_data)
+{
+ TestData *d = user_data;
+ struct termios stbuf;
+ int ret;
+ GError *error = NULL;
+ gboolean success;
+
+ ret = openpty (&d->master, &d->slave, NULL, NULL, NULL);
+ g_assert (ret == 0);
+ d->valid = TRUE;
+
+ /* set raw mode on the slave using kernel default parameters */
+ memset (&stbuf, 0, sizeof (stbuf));
+ tcgetattr (d->slave, &stbuf);
+ tcflush (d->slave, TCIOFLUSH);
+ cfmakeraw (&stbuf);
+ tcsetattr (d->slave, TCSANOW, &stbuf);
+ fcntl (d->slave, F_SETFL, O_NONBLOCK);
+
+ fcntl (d->master, F_SETFL, O_NONBLOCK);
+ success = qcdm_port_setup (d->master, &error);
+ g_assert_no_error (error);
+ g_assert (success);
+}
+
+static void
+test_pty_cleanup (gpointer user_data)
+{
+ TestData *d = user_data;
+
+ /* For some reason the cleanup function gets called more times
+ * than the setup function does...
+ */
+ if (d->valid) {
+ if (d->child)
+ kill (d->child, SIGKILL);
+ if (d->master >= 0)
+ close (d->master);
+ if (d->slave >= 0)
+ close (d->slave);
+ memset (d, 0, sizeof (*d));
+ }
+}
+
+#if GLIB_CHECK_VERSION(2,25,12)
+typedef GTestFixtureFunc TCFunc;
+#else
+typedef void (*TCFunc)(void);
+#endif
+
+#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL)
+#define TESTCASE_PTY(t, d) g_test_create_case (#t, sizeof (*d), d, (TCFunc) test_pty_create, (TCFunc) t, (TCFunc) test_pty_cleanup)
+
+void
+_mm_log (const char *loc,
+ const char *func,
+ guint32 level,
+ const char *fmt,
+ ...)
+{
+ /* Dummy log function */
+}
+
+int main (int argc, char **argv)
+{
+ GTestSuite *suite;
+ gint result;
+ TestData *data = NULL;
+
+ g_test_init (&argc, &argv, NULL);
+
+ suite = g_test_get_root ();
+
+ g_test_suite_add (suite, TESTCASE_PTY (test_verinfo, data));
+ g_test_suite_add (suite, TESTCASE_PTY (test_sierra_cns_rejected, data));
+ g_test_suite_add (suite, TESTCASE_PTY (test_random_data_rejected, data));
+ g_test_suite_add (suite, TESTCASE_PTY (test_leading_frame_markers, data));
+
+ result = g_test_run ();
+
+ return result;
+}
+
diff --git a/test/Makefile.am b/test/Makefile.am
index 3d571c3..2fbc519 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -19,5 +19,11 @@ lsudev_LDADD = $(GUDEV_LIBS)
EXTRA_DIST = \
- mm-test.py
+ mm-test.py \
+ disable.py \
+ enable.py \
+ info.py \
+ list-modems.py \
+ location.py \
+ mm-send-sms.py
diff --git a/test/disable.py b/test/disable.py
new file mode 100755
index 0000000..5b8c14a
--- /dev/null
+++ b/test/disable.py
@@ -0,0 +1,27 @@
+#!/usr/bin/python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details:
+#
+# Copyright (C) 2009 - 2010 Red Hat, Inc.
+#
+
+import sys, dbus
+
+MM_DBUS_SERVICE='org.freedesktop.ModemManager'
+MM_DBUS_PATH='/org/freedesktop/ModemManager'
+MM_DBUS_INTERFACE_MODEM='org.freedesktop.ModemManager.Modem'
+
+bus = dbus.SystemBus()
+proxy = bus.get_object(MM_DBUS_SERVICE, sys.argv[1])
+modem = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM)
+modem.Enable (False)
+
diff --git a/test/enable.py b/test/enable.py
new file mode 100755
index 0000000..bfe1a6d
--- /dev/null
+++ b/test/enable.py
@@ -0,0 +1,27 @@
+#!/usr/bin/python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details:
+#
+# Copyright (C) 2009 - 2010 Red Hat, Inc.
+#
+
+import sys, dbus
+
+MM_DBUS_SERVICE='org.freedesktop.ModemManager'
+MM_DBUS_PATH='/org/freedesktop/ModemManager'
+MM_DBUS_INTERFACE_MODEM='org.freedesktop.ModemManager.Modem'
+
+bus = dbus.SystemBus()
+proxy = bus.get_object(MM_DBUS_SERVICE, sys.argv[1])
+modem = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM)
+modem.Enable (True)
+
diff --git a/test/info.py b/test/info.py
new file mode 100755
index 0000000..6659a3a
--- /dev/null
+++ b/test/info.py
@@ -0,0 +1,256 @@
+#!/usr/bin/python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details:
+#
+# Copyright (C) 2008 Novell, Inc.
+# Copyright (C) 2009 Red Hat, Inc.
+#
+
+import sys, dbus
+
+DBUS_INTERFACE_PROPERTIES='org.freedesktop.DBus.Properties'
+MM_DBUS_SERVICE='org.freedesktop.ModemManager'
+MM_DBUS_PATH='/org/freedesktop/ModemManager'
+MM_DBUS_INTERFACE='org.freedesktop.ModemManager'
+MM_DBUS_INTERFACE_MODEM='org.freedesktop.ModemManager.Modem'
+MM_DBUS_INTERFACE_MODEM_CDMA='org.freedesktop.ModemManager.Modem.Cdma'
+MM_DBUS_INTERFACE_MODEM_GSM_CARD='org.freedesktop.ModemManager.Modem.Gsm.Card'
+MM_DBUS_INTERFACE_MODEM_GSM_NETWORK='org.freedesktop.ModemManager.Modem.Gsm.Network'
+
+def get_cdma_band_class(band_class):
+ if band_class == 1:
+ return "800MHz"
+ elif band_class == 2:
+ return "1900MHz"
+ else:
+ return "Unknown"
+
+def get_reg_state(state):
+ if state == 1:
+ return "registered (roaming unknown)"
+ elif state == 2:
+ return "registered on home network"
+ elif state == 3:
+ return "registered on roaming network"
+ else:
+ return "unknown"
+
+def cdma_inspect(proxy, props):
+ cdma = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM_CDMA)
+
+ esn = cdma.GetEsn()
+ print "ESN: %s" % esn
+
+ try:
+ (cdma_1x_state, evdo_state) = cdma.GetRegistrationState()
+ print "1x State: %s" % get_reg_state (cdma_1x_state)
+ print "EVDO State: %s" % get_reg_state (evdo_state)
+ except dbus.exceptions.DBusException, e:
+ print "Error reading registration state: %s" % e
+
+ try:
+ quality = cdma.GetSignalQuality()
+ print "Signal quality: %d" % quality
+ except dbus.exceptions.DBusException, e:
+ print "Error reading signal quality: %s" % e
+
+ try:
+ info = cdma.GetServingSystem()
+ print "Class: %s" % get_cdma_band_class(info[0])
+ print "Band: %s" % info[1]
+ print "SID: %d" % info[2]
+ except dbus.exceptions.DBusException, e:
+ print "Error reading serving system: %s" % e
+
+
+def get_gsm_network_mode(modem):
+ mode = modem.GetNetworkMode()
+ if mode == 0x0:
+ mode = "Unknown"
+ elif mode == 0x1:
+ mode = "Any"
+ elif mode == 0x2:
+ mode = "GPRS"
+ elif mode == 0x4:
+ mode = "EDGE"
+ elif mode == 0x8:
+ mode = "UMTS"
+ elif mode == 0x10:
+ mode = "HSDPA"
+ elif mode == 0x20:
+ mode = "2G Preferred"
+ elif mode == 0x40:
+ mode = "3G Preferred"
+ elif mode == 0x80:
+ mode = "2G Only"
+ elif mode == 0x100:
+ mode = "3G Only"
+ elif mode == 0x200:
+ mode = "HSUPA"
+ elif mode == 0x400:
+ mode = "HSPA"
+ else:
+ mode = "(Unknown)"
+
+ print "Mode: %s" % mode
+
+def get_gsm_band(modem):
+ band = modem.GetBand()
+ if band == 0x0:
+ band = "Unknown"
+ elif band == 0x1:
+ band = "Any"
+ elif band == 0x2:
+ band = "EGSM (900 MHz)"
+ elif band == 0x4:
+ band = "DCS (1800 MHz)"
+ elif band == 0x8:
+ band = "PCS (1900 MHz)"
+ elif band == 0x10:
+ band = "G850 (850 MHz)"
+ elif band == 0x20:
+ band = "U2100 (WCSMA 2100 MHZ, Class I)"
+ elif band == 0x40:
+ band = "U1700 (WCDMA 3GPP UMTS1800 MHz, Class III)"
+ elif band == 0x80:
+ band = "17IV (WCDMA 3GPP AWS 1700/2100 MHz, Class IV)"
+ elif band == 0x100:
+ band = "U800 (WCDMA 3GPP UMTS800 MHz, Class VI)"
+ elif band == 0x200:
+ band = "U850 (WCDMA 3GPP UMT850 MHz, Class V)"
+ elif band == 0x400:
+ band = "U900 (WCDMA 3GPP UMTS900 MHz, Class VIII)"
+ elif band == 0x800:
+ band = "U17IX (WCDMA 3GPP UMTS MHz, Class IX)"
+ else:
+ band = "(invalid)"
+
+ print "Band: %s" % band
+
+
+mm_allowed = { 0: "any",
+ 1: "2G preferred",
+ 2: "3G preferred",
+ 3: "2G only",
+ 4: "3G only"
+ }
+
+mm_act = { 0: "unknown",
+ 1: "GSM",
+ 2: "GSM Compact",
+ 3: "GPRS",
+ 4: "EDGE",
+ 5: "UMTS",
+ 6: "HSDPA",
+ 7: "HSUPA",
+ 8: "HSPA"
+ }
+
+mm_reg = { 0: "idle",
+ 1: "home",
+ 2: "searching",
+ 3: "denied",
+ 4: "unknown",
+ 5: "roaming"
+ }
+
+def gsm_inspect(proxy, props):
+ # Gsm.Card interface
+ card = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM_GSM_CARD)
+
+ simid = "<unavailable>"
+ try:
+ simid = props.Get(MM_DBUS_INTERFACE_MODEM_GSM_CARD, "SimIdentifier")
+ except dbus.exceptions.DBusException:
+ pass
+ print "SIM ID: %s" % simid
+
+ imei = "<unavailable>"
+ try:
+ imei = card.GetImei()
+ except dbus.exceptions.DBusException:
+ pass
+ print "IMEI: %s" % imei
+
+ imsi = "<unavailable>"
+ try:
+ imsi = card.GetImsi()
+ except dbus.exceptions.DBusException:
+ pass
+ print "IMSI: %s" % imsi
+
+ opid = "<unavailable>"
+ try:
+ opid = card.GetOperatorId()
+ except dbus.exceptions.DBusException:
+ pass
+ print "Operator ID: %s" % opid
+
+ # Gsm.Network interface
+ net = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM_GSM_NETWORK)
+ try:
+ quality = net.GetSignalQuality()
+ print "Signal quality: %d" % quality
+ except dbus.exceptions.DBusException, e:
+ print "Error reading signal quality: %s" % e
+
+ try:
+ reg = net.GetRegistrationInfo()
+ print "Reg status: %s (%s, '%s')" % (mm_reg[int(reg[0])], reg[1], reg[2])
+ except dbus.exceptions.DBusException, e:
+ print "Error reading registration: %s" % e
+
+ try:
+ allowed = props.Get(MM_DBUS_INTERFACE_MODEM_GSM_NETWORK, "AllowedMode")
+ print "Allowed mode: %s" % mm_allowed[allowed]
+ except dbus.exceptions.DBusException, e:
+ print "Error reading allowed mode: %s" % e
+
+ try:
+ act = props.Get(MM_DBUS_INTERFACE_MODEM_GSM_NETWORK, "AccessTechnology")
+ print "Access Tech: %s" % mm_act[act]
+ except dbus.exceptions.DBusException, e:
+ print "Error reading current access technology: %s" % e
+
+
+
+bus = dbus.SystemBus()
+bus = dbus.SystemBus()
+proxy = bus.get_object(MM_DBUS_SERVICE, sys.argv[1])
+
+# Properties
+props = dbus.Interface(proxy, dbus_interface='org.freedesktop.DBus.Properties')
+
+mtype = props.Get(MM_DBUS_INTERFACE_MODEM, 'Type')
+if mtype == 1:
+ print "Type: GSM"
+elif mtype == 2:
+ print "Type: CDMA"
+
+print "Driver: %s" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'Driver'))
+print "Modem device: %s" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'MasterDevice'))
+print "Data device: %s" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'Device'))
+print "Device ID: %s" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'DeviceIdentifier'))
+print ""
+
+modem = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM)
+info = modem.GetInfo()
+print "Vendor: %s" % info[0]
+print "Model: %s" % info[1]
+print "Version: %s" % info[2]
+print ""
+
+if mtype == 1:
+ gsm_inspect(proxy, props)
+elif mtype == 2:
+ cdma_inspect(proxy, props)
+
diff --git a/test/list-modems.py b/test/list-modems.py
new file mode 100755
index 0000000..c8cd618
--- /dev/null
+++ b/test/list-modems.py
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details:
+#
+# Copyright (C) 2008 Novell, Inc.
+# Copyright (C) 2009 - 2010 Red Hat, Inc.
+#
+
+import sys, dbus
+
+DBUS_INTERFACE_PROPERTIES='org.freedesktop.DBus.Properties'
+MM_DBUS_SERVICE='org.freedesktop.ModemManager'
+MM_DBUS_PATH='/org/freedesktop/ModemManager'
+MM_DBUS_INTERFACE='org.freedesktop.ModemManager'
+MM_DBUS_INTERFACE_MODEM='org.freedesktop.ModemManager.Modem'
+
+bus = dbus.SystemBus()
+
+# Get available modems:
+manager_proxy = bus.get_object(MM_DBUS_SERVICE, MM_DBUS_PATH)
+manager_iface = dbus.Interface(manager_proxy, dbus_interface=MM_DBUS_INTERFACE)
+modems = manager_iface.EnumerateDevices()
+
+if not modems:
+ print "No modems found"
+ sys.exit(1)
+
+for m in modems:
+ proxy = bus.get_object(MM_DBUS_SERVICE, m)
+
+ # Properties
+ props_iface = dbus.Interface(proxy, dbus_interface=DBUS_INTERFACE_PROPERTIES)
+
+ driver = props_iface.Get(MM_DBUS_INTERFACE_MODEM, 'Driver')
+ mtype = props_iface.Get(MM_DBUS_INTERFACE_MODEM, 'Type')
+ device = props_iface.Get(MM_DBUS_INTERFACE_MODEM, 'MasterDevice')
+
+ strtype = ""
+ if mtype == 1:
+ strtype = "GSM"
+ elif mtype == 2:
+ strtype = "CDMA"
+
+ print "%s (%s [%s], device %s)" % (m, strtype, driver, device)
+
diff --git a/test/location.py b/test/location.py
new file mode 100755
index 0000000..b6af387
--- /dev/null
+++ b/test/location.py
@@ -0,0 +1,57 @@
+#!/usr/bin/python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details:
+#
+# Copyright (C) 2009 - 2010 Red Hat, Inc.
+#
+
+import sys, dbus, time
+
+DBUS_INTERFACE_PROPERTIES='org.freedesktop.DBus.Properties'
+MM_DBUS_SERVICE='org.freedesktop.ModemManager'
+MM_DBUS_PATH='/org/freedesktop/ModemManager'
+MM_DBUS_INTERFACE='org.freedesktop.ModemManager'
+MM_DBUS_INTERFACE_MODEM='org.freedesktop.ModemManager.Modem'
+MM_DBUS_INTERFACE_MODEM_LOCATION='org.freedesktop.ModemManager.Modem.Location'
+
+MM_MODEM_LOCATION_CAPABILITY_UNKNOWN = 0x00000000
+MM_MODEM_LOCATION_CAPABILITY_GPS_NMEA = 0x00000001
+MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI = 0x00000002
+MM_MODEM_LOCATION_CAPABILITY_GPS_RAW = 0x00000004
+
+bus = dbus.SystemBus()
+proxy = bus.get_object(MM_DBUS_SERVICE, sys.argv[1])
+modem = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM)
+
+props = dbus.Interface(proxy, dbus_interface=DBUS_INTERFACE_PROPERTIES)
+caps = props.Get(MM_DBUS_INTERFACE_MODEM_LOCATION, "Capabilities")
+
+print "Location Capabilities:"
+if caps & MM_MODEM_LOCATION_CAPABILITY_GPS_NMEA:
+ print " GPS_NMEA"
+if caps & MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI:
+ print " GSM_LAC_CI"
+if caps & MM_MODEM_LOCATION_CAPABILITY_GPS_RAW:
+ print " GPS_RAW"
+print ""
+
+loc = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM_LOCATION)
+loc.Enable(True, True)
+
+for i in range(0, 5):
+ locations = loc.GetLocation()
+ if locations.has_key(MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI):
+ print "GSM_LAC_CI: %s" % str(locations[MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI])
+ time.sleep(1)
+
+loc.Enable(False, False)
+
diff --git a/test/scan.py b/test/scan.py
new file mode 100755
index 0000000..c892e65
--- /dev/null
+++ b/test/scan.py
@@ -0,0 +1,101 @@
+#!/usr/bin/python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details:
+#
+# Copyright (C) 2009 - 2010Red Hat, Inc.
+#
+
+import sys, dbus
+
+DBUS_INTERFACE_PROPERTIES='org.freedesktop.DBus.Properties'
+MM_DBUS_SERVICE='org.freedesktop.ModemManager'
+MM_DBUS_INTERFACE_MODEM='org.freedesktop.ModemManager.Modem'
+MM_DBUS_INTERFACE_MODEM_GSM_NETWORK='org.freedesktop.ModemManager.Modem.Gsm.Network'
+
+mm_act = { 0: "unknown",
+ 1: "GSM",
+ 2: "GSM Compact",
+ 3: "GPRS",
+ 4: "EDGE",
+ 5: "UMTS",
+ 6: "HSDPA",
+ 7: "HSUPA",
+ 8: "HSPA"
+ }
+
+bus = dbus.SystemBus()
+proxy = bus.get_object(MM_DBUS_SERVICE, sys.argv[1])
+
+# Properties
+props = dbus.Interface(proxy, dbus_interface='org.freedesktop.DBus.Properties')
+
+mtype = props.Get(MM_DBUS_INTERFACE_MODEM, 'Type')
+if mtype == 2:
+ print "CDMA modems do not support network scans"
+ sys.exit(1)
+
+print "Driver: '%s'" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'Driver'))
+print "Modem device: '%s'" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'MasterDevice'))
+print "Data device: '%s'" % (props.Get(MM_DBUS_INTERFACE_MODEM, 'Device'))
+print ""
+
+net = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM_GSM_NETWORK)
+print "Scanning..."
+try:
+ results = net.Scan(timeout=120)
+except dbus.exceptions.DBusException, e:
+ print "Error scanning: %s" % e
+ results = {}
+
+for r in results:
+ status = r['status']
+ if status == "1":
+ status = "available"
+ elif status == "2":
+ status = "current"
+ elif status == "3":
+ status = "forbidden"
+ else:
+ status = "(Unknown)"
+
+ access_tech = ""
+ try:
+ access_tech_num = int(r['access-tech'])
+ if access_tech_num == "0":
+ access_tech = "(GSM)"
+ elif access_tech_num == "1":
+ access_tech = "(Compact GSM)"
+ elif access_tech_num == "2":
+ access_tech = "(UMTS)"
+ elif access_tech_num == "3":
+ access_tech = "(EDGE)"
+ elif access_tech_num == "4":
+ access_tech = "(HSDPA)"
+ elif access_tech_num == "5":
+ access_tech = "(HSUPA)"
+ elif access_tech_num == "6":
+ access_tech = "(HSPA)"
+ except KeyError:
+ pass
+
+ opnum = "(%s):" % r['operator-num']
+ # Extra space for 5-digit MCC/MNC
+ if r['operator-num'] == 5:
+ opnum += " "
+
+ if r.has_key('operator-long') and len(r['operator-long']):
+ print "%s %s %s %s" % (r['operator-long'], opnum, status, access_tech)
+ elif r.has_key('operator-short') and len(r['operator-short']):
+ print "%s %s %s %s" % (r['operator-short'], opnum, status, access_tech)
+ else:
+ print "%s: %s %s" % (r['operator-num'], status, access_tech)
+
diff --git a/test/ussd.py b/test/ussd.py
new file mode 100755
index 0000000..2040f12
--- /dev/null
+++ b/test/ussd.py
@@ -0,0 +1,44 @@
+#!/usr/bin/python
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details:
+#
+# Copyright (C) 2010 Guido Guenther <agx@sigxcpu.org>
+#
+# Usage: ./test/ussd.py /org/freedesktop/ModemManager/Modems/0 '*130#'
+
+import sys, dbus, re
+
+MM_DBUS_SERVICE='org.freedesktop.ModemManager'
+MM_DBUS_INTERFACE_USSD='org.freedesktop.ModemManager.Modem.Gsm.Ussd'
+
+bus = dbus.SystemBus()
+proxy = bus.get_object(MM_DBUS_SERVICE, sys.argv[1])
+modem = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_USSD)
+
+if len(sys.argv) != 3:
+ print "Usage: %s dbus_object ussd"
+ sys.exit(1)
+else:
+ arg = sys.argv[2]
+
+# For testing purposes treat all "common" USSD sequences as initiate and the
+# rest (except for cancel) as response. See GSM 02.90.
+initiate_re = re.compile('[*#]{1,3}1[0-9][0-9].*#')
+
+if initiate_re.match(arg):
+ ret = modem.Initiate(arg)
+elif arg == "cancel":
+ ret = modem.Cancel()
+else:
+ ret = modem.Respond(arg)
+print ret
+