aboutsummaryrefslogtreecommitdiff
path: root/plugins
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
commitdc645b92b9a7db3076ae34986ac219d01677d124 (patch)
tree963a5d6ad150a88a2a8ab6d994d79d539e19383a /plugins
parent87bd9deec22af69bb27226254803ac5c63b18d78 (diff)
Imported Upstream version 0.4+git.20100624t180933.6e79d15upstream/0.4+git.20100624t180933.6e79d15
Diffstat (limited to 'plugins')
-rw-r--r--plugins/77-mm-ericsson-mbm.rules10
-rw-r--r--plugins/77-mm-longcheer-port-types.rules134
-rw-r--r--plugins/77-mm-simtech-port-types.rules29
-rw-r--r--plugins/Makefile.am35
-rw-r--r--plugins/mm-modem-anydata-cdma.c86
-rw-r--r--plugins/mm-modem-gobi-gsm.c14
-rw-r--r--plugins/mm-modem-hso.c602
-rw-r--r--plugins/mm-modem-huawei-cdma.c73
-rw-r--r--plugins/mm-modem-huawei-gsm.c705
-rw-r--r--plugins/mm-modem-longcheer-gsm.c222
-rw-r--r--plugins/mm-modem-longcheer-gsm.h43
-rw-r--r--plugins/mm-modem-mbm.c578
-rw-r--r--plugins/mm-modem-mbm.h4
-rw-r--r--plugins/mm-modem-nokia.c14
-rw-r--r--plugins/mm-modem-novatel-cdma.c183
-rw-r--r--plugins/mm-modem-novatel-cdma.h45
-rw-r--r--plugins/mm-modem-novatel-gsm.c276
-rw-r--r--plugins/mm-modem-option-utils.c451
-rw-r--r--plugins/mm-modem-option.c256
-rw-r--r--plugins/mm-modem-sierra-cdma.c148
-rw-r--r--plugins/mm-modem-sierra-gsm.c268
-rw-r--r--plugins/mm-modem-simtech-gsm.c471
-rw-r--r--plugins/mm-modem-simtech-gsm.h43
-rw-r--r--plugins/mm-modem-zte.c329
-rw-r--r--plugins/mm-plugin-anydata.c30
-rw-r--r--plugins/mm-plugin-generic.c28
-rw-r--r--plugins/mm-plugin-gobi.c21
-rw-r--r--plugins/mm-plugin-hso.c11
-rw-r--r--plugins/mm-plugin-huawei.c75
-rw-r--r--plugins/mm-plugin-longcheer.c38
-rw-r--r--plugins/mm-plugin-mbm.c38
-rw-r--r--plugins/mm-plugin-mbm.h4
-rw-r--r--plugins/mm-plugin-moto-c.c31
-rw-r--r--plugins/mm-plugin-nokia.c21
-rw-r--r--plugins/mm-plugin-novatel.c40
-rw-r--r--plugins/mm-plugin-option.c24
-rw-r--r--plugins/mm-plugin-sierra.c22
-rw-r--r--plugins/mm-plugin-simtech.c189
-rw-r--r--plugins/mm-plugin-simtech.h41
-rw-r--r--plugins/mm-plugin-zte.c28
40 files changed, 4254 insertions, 1406 deletions
diff --git a/plugins/77-mm-ericsson-mbm.rules b/plugins/77-mm-ericsson-mbm.rules
index 71dc6b8..8804036 100644
--- a/plugins/77-mm-ericsson-mbm.rules
+++ b/plugins/77-mm-ericsson-mbm.rules
@@ -20,9 +20,15 @@ ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1909", 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"
+
# 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"
+
# Dell 5530 HSDPA
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8147", ENV{ID_MM_ERICSSON_MBM}="1"
@@ -30,6 +36,10 @@ ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8147", ENV{ID_MM_ERICSSON_MBM}="1"
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8183", ENV{ID_MM_ERICSSON_MBM}="1"
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8184", ENV{ID_MM_ERICSSON_MBM}="1"
+# Dell F3307
+ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818b", ENV{ID_MM_ERICSSON_MBM}="1"
+ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818c", ENV{ID_MM_ERICSSON_MBM}="1"
+
# Toshiba
ATTRS{idVendor}=="0930", ATTRS{idProduct}=="130b", ENV{ID_MM_ERICSSON_MBM}="1"
diff --git a/plugins/77-mm-longcheer-port-types.rules b/plugins/77-mm-longcheer-port-types.rules
index 7317df7..ce0134b 100644
--- a/plugins/77-mm-longcheer-port-types.rules
+++ b/plugins/77-mm-longcheer-port-types.rules
@@ -6,6 +6,11 @@
# Alcatel One Touch X030
# MobiData MBD-200HU
# ST Mobile Connect HSUPA USB Modem
+#
+# Most of these values were scraped from various Longcheer-based Windows
+# driver .inf files. cmmdm.inf lists the actual data (ie PPP) ports, while
+# cmser.inf lists the aux ports that may be either AT-capable or not but
+# cannot be used for PPP.
ACTION!="add|change", GOTO="mm_longcheer_port_types_end"
@@ -18,6 +23,14 @@ GOTO="mm_longcheer_port_types_end"
LABEL="mm_longcheer_vendorcheck"
SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
+ATTRS{idProduct}=="3197", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="3197", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="3197", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="6000", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="6000", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="6000", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
ATTRS{idProduct}=="6060", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
ATTRS{idProduct}=="6060", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
ATTRS{idProduct}=="6060", ENV{ID_MM_LONGCHEER_TAGGED}="1"
@@ -27,6 +40,127 @@ ATTRS{idProduct}=="6061", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE
ATTRS{idProduct}=="6061", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
ATTRS{idProduct}=="6061", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+ATTRS{idProduct}=="7001", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="7001", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="7001", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="7001", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="7002", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="7002", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="7002", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="7002", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="7002", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="7101", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="7101", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="7101", ENV{.MM_USBIFNUM}=="05", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="7101", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="7102", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="7102", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="7102", ENV{.MM_USBIFNUM}=="05", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="7102", ENV{.MM_USBIFNUM}=="06", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="7102", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="8000", ENV{.MM_USBIFNUM}=="05", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="8000", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="8000", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="8000", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="8001", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="8001", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="8001", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="8001", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="8002", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="8002", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="8002", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="8002", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+# ChinaBird PL68
+ATTRS{idProduct}=="9000", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9000", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9000", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="9001", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9001", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9001", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9001", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="9002", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9002", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9002", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9002", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="9003", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9003", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9003", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9003", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9003", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="9004", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9004", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9004", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="9005", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9005", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9005", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="9010", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9010", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9010", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9010", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="9012", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9012", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9012", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9012", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="9020", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9020", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9020", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9020", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="9022", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9022", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9022", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9022", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+# Zoom products
+ATTRS{idProduct}=="9602", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9602", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9602", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9602", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="9603", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9603", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9603", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9603", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="9604", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9604", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9604", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9604", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="9605", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9605", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9605", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9605", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9605", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="9606", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9606", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9606", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9606", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9606", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+ATTRS{idProduct}=="9607", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9607", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9607", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9607", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9607", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9607", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
GOTO="mm_longcheer_port_types_end"
diff --git a/plugins/77-mm-simtech-port-types.rules b/plugins/77-mm-simtech-port-types.rules
new file mode 100644
index 0000000..9ec047c
--- /dev/null
+++ b/plugins/77-mm-simtech-port-types.rules
@@ -0,0 +1,29 @@
+# do not edit this file, it will be overwritten on update
+
+# Simtech makes modules that other companies rebrand, like:
+#
+# A-LINK 3GU
+#
+# Most of these values were scraped from various SimTech-based Windows
+# driver .inf files. *mdm.inf lists the main command ports, while
+# *ser.inf lists the aux ports that may be used for PPP.
+
+
+ACTION!="add|change", GOTO="mm_simtech_port_types_end"
+SUBSYSTEM!="tty", GOTO="mm_simtech_port_types_end"
+
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="1e0e", GOTO="mm_alink_vendorcheck"
+GOTO="mm_simtech_port_types_end"
+
+LABEL="mm_alink_vendorcheck"
+SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
+
+ATTRS{idProduct}=="9200", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_SIMTECH_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="9200", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_SIMTECH_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="9200", ENV{ID_MM_SIMTECH_TAGGED}="1"
+
+GOTO="mm_simtech_port_types_end"
+
+
+LABEL="mm_simtech_port_types_end"
+
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index a361358..8192653 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -11,7 +11,8 @@ pkglib_LTLIBRARIES = \
libmm-plugin-zte.la \
libmm-plugin-mbm.la \
libmm-plugin-longcheer.la \
- libmm-plugin-anydata.la
+ libmm-plugin-anydata.la \
+ libmm-plugin-simtech.la
# Generic
@@ -169,7 +170,9 @@ libmm_plugin_novatel_la_SOURCES = \
mm-plugin-novatel.c \
mm-plugin-novatel.h \
mm-modem-novatel-gsm.c \
- mm-modem-novatel-gsm.h
+ mm-modem-novatel-gsm.h \
+ mm-modem-novatel-cdma.c \
+ mm-modem-novatel-cdma.h
libmm_plugin_novatel_la_CPPFLAGS = \
$(MM_CFLAGS) \
@@ -221,7 +224,9 @@ libmm_plugin_zte_la_LDFLAGS = \
libmm_plugin_longcheer_la_SOURCES = \
mm-plugin-longcheer.c \
- mm-plugin-longcheer.h
+ mm-plugin-longcheer.h \
+ mm-modem-longcheer-gsm.c \
+ mm-modem-longcheer-gsm.h
libmm_plugin_longcheer_la_CPPFLAGS = \
$(MM_CFLAGS) \
@@ -251,12 +256,31 @@ libmm_plugin_anydata_la_LDFLAGS = \
-module \
-avoid-version
+# SimTech
+
+libmm_plugin_simtech_la_SOURCES = \
+ mm-plugin-simtech.c \
+ mm-plugin-simtech.h \
+ mm-modem-simtech-gsm.c \
+ mm-modem-simtech-gsm.h
+
+libmm_plugin_simtech_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_simtech_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-longcheer-port-types.rules \
+ 77-mm-simtech-port-types.rules
BUILT_SOURCES = \
mm-modem-gsm-hso-glue.h
@@ -264,5 +288,6 @@ BUILT_SOURCES = \
CLEANFILES = $(BUILT_SOURCES)
EXTRA_DIST = \
- $(udevrules_DATA)
+ $(udevrules_DATA) \
+ mm-modem-option-utils.c
diff --git a/plugins/mm-modem-anydata-cdma.c b/plugins/mm-modem-anydata-cdma.c
index f6528ec..c7cca46 100644
--- a/plugins/mm-modem-anydata-cdma.c
+++ b/plugins/mm-modem-anydata-cdma.c
@@ -112,7 +112,7 @@ int_from_match_item (GMatchInfo *match_info, guint32 num, gint *val)
}
static void
-evdo_state_done (MMSerialPort *port,
+evdo_state_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -123,15 +123,8 @@ evdo_state_done (MMSerialPort *port,
GRegex *r;
GMatchInfo *match_info;
- info->error = mm_modem_check_removed (info->modem, error);
- if (info->error) {
- if (info->modem) {
- /* If HSTATE returned an error, assume the device is not EVDO capable
- * or EVDO is not registered.
- */
- mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- }
-
+ if (error) {
+ /* Leave superclass' reg state alone if AT*HSTATE isn't supported */
mm_callback_info_schedule (info);
return;
}
@@ -143,13 +136,8 @@ evdo_state_done (MMSerialPort *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): failed to create EVDO state regex: (%d) %s",
- __func__,
- error ? error->code : -1,
- error && error->message ? error->message : "(unknown)");
- mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- mm_callback_info_schedule (info);
- return;
+ g_warning ("AnyDATA(%s): *HSTATE parse regex creation failed.", __func__);
+ goto done;
}
g_regex_match (r, reply, 0, &match_info);
@@ -185,13 +173,13 @@ evdo_state_done (MMSerialPort *port,
}
}
+done:
mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, reg_state);
-
mm_callback_info_schedule (info);
}
static void
-state_done (MMSerialPort *port,
+state_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -202,17 +190,8 @@ state_done (MMSerialPort *port,
GRegex *r;
GMatchInfo *match_info;
- info->error = mm_modem_check_removed (info->modem, error);
- if (info->error) {
- if (info->modem) {
- /* Assume if we got this far, we're registered even if an error
- * occurred. We're not sure if all AnyData CDMA modems support
- * the *STATE and *HSTATE commands.
- */
- mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED);
- mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
- }
-
+ if (error) {
+ /* Leave superclass' reg state alone if AT*STATE isn't supported */
mm_callback_info_schedule (info);
return;
}
@@ -223,9 +202,7 @@ state_done (MMSerialPort *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) {
- info->error = g_error_new_literal (MM_MODEM_ERROR,
- MM_MODEM_ERROR_GENERAL,
- "Could not parse sysinfo results (regex creation failed).");
+ g_warning ("AnyDATA(%s): *STATE parse regex creation failed.", __func__);
mm_callback_info_schedule (info);
return;
}
@@ -254,7 +231,7 @@ state_done (MMSerialPort *port,
reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
break;
default:
- g_message ("ANYDATA: unknown *STATE (%d); assuming no service.", val);
+ g_warning ("ANYDATA: unknown *STATE (%d); assuming no service.", val);
/* fall through */
case 0: /* NO SERVICE */
break;
@@ -265,35 +242,28 @@ state_done (MMSerialPort *port,
mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state);
/* Try for EVDO state too */
- mm_serial_port_queue_command (port, "*HSTATE?", 3, evdo_state_done, info);
+ mm_at_serial_port_queue_command (port, "*HSTATE?", 3, evdo_state_done, info);
}
static void
query_registration_state (MMGenericCdma *cdma,
+ MMModemCdmaRegistrationState cur_cdma_state,
+ MMModemCdmaRegistrationState cur_evdo_state,
MMModemCdmaRegistrationStateFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
- MMSerialPort *primary, *secondary, *port;
-
- port = primary = mm_generic_cdma_get_port (cdma, MM_PORT_TYPE_PRIMARY);
- secondary = mm_generic_cdma_get_port (cdma, MM_PORT_TYPE_SECONDARY);
-
- info = mm_generic_cdma_query_reg_state_callback_info_new (cdma, callback, user_data);
+ MMAtSerialPort *port;
- if (mm_port_get_connected (MM_PORT (primary))) {
- if (!secondary) {
- info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_CONNECTED,
- "Cannot get query registration state while connected");
- mm_callback_info_schedule (info);
- return;
- }
+ info = mm_generic_cdma_query_reg_state_callback_info_new (cdma, cur_cdma_state, cur_evdo_state, callback, user_data);
- /* Use secondary port if primary is connected */
- port = secondary;
+ port = mm_generic_cdma_get_best_at_port (cdma, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
}
- mm_serial_port_queue_command (port, "*STATE?", 3, state_done, info);
+ mm_at_serial_port_queue_command (port, "*STATE?", 3, state_done, info);
}
/*****************************************************************************/
@@ -310,22 +280,22 @@ grab_port (MMModem *modem,
GRegex *regex;
port = mm_generic_cdma_grab_port (MM_GENERIC_CDMA (modem), subsys, name, suggested_type, user_data, error);
- if (port && MM_IS_SERIAL_PORT (port)) {
+ if (port && MM_IS_AT_SERIAL_PORT (port)) {
/* Data state notifications */
/* Data call has connected */
regex = g_regex_new ("\\r\\n\\*ACTIVE:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
g_regex_unref (regex);
/* Data call disconnected */
regex = g_regex_new ("\\r\\n\\*INACTIVE:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
g_regex_unref (regex);
/* Modem is now dormant */
regex = g_regex_new ("\\r\\n\\*DORMANT:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
g_regex_unref (regex);
/* Abnomral state notifications
@@ -336,17 +306,17 @@ grab_port (MMModem *modem,
/* Network acquisition fail */
regex = g_regex_new ("\\r\\n\\*OFFLINE:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
g_regex_unref (regex);
/* Registration fail */
regex = g_regex_new ("\\r\\n\\*REGREQ:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
g_regex_unref (regex);
/* Authentication fail */
regex = g_regex_new ("\\r\\n\\*AUTHREQ:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
g_regex_unref (regex);
}
diff --git a/plugins/mm-modem-gobi-gsm.c b/plugins/mm-modem-gobi-gsm.c
index 7ea9f8f..3b9e9ec 100644
--- a/plugins/mm-modem-gobi-gsm.c
+++ b/plugins/mm-modem-gobi-gsm.c
@@ -23,6 +23,7 @@
#include "mm-errors.h"
#include "mm-callback-info.h"
#include "mm-modem-gsm-card.h"
+#include "mm-at-serial-port.h"
static void modem_init (MMModem *modem_class);
static void modem_gsm_card_init (MMModemGsmCard *gsm_card_class);
@@ -51,7 +52,7 @@ mm_modem_gobi_gsm_new (const char *device,
/*****************************************************************************/
static void
-get_string_done (MMSerialPort *port,
+get_string_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -75,13 +76,16 @@ get_imsi (MMModemGsmCard *modem,
MMModemStringFn callback,
gpointer user_data)
{
- MMSerialPort *primary;
+ MMAtSerialPort *port;
MMCallbackInfo *info;
info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
- mm_serial_port_queue_command_cached (primary, "+CIMI", 3, get_string_done, info);
+
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error);
+ if (port)
+ mm_at_serial_port_queue_command_cached (port, "+CIMI", 3, get_string_done, info);
+ else
+ mm_callback_info_schedule (info);
}
static void
diff --git a/plugins/mm-modem-hso.c b/plugins/mm-modem-hso.c
index f1295e2..1fd4633 100644
--- a/plugins/mm-modem-hso.c
+++ b/plugins/mm-modem-hso.c
@@ -63,6 +63,9 @@ typedef struct {
MMCallbackInfo *connect_pending_data;
guint connect_pending_id;
+ char *username;
+ char *password;
+
guint32 auth_idx;
} MMModemHsoPrivate;
@@ -85,62 +88,122 @@ mm_modem_hso_new (const char *device,
NULL));
}
-#define IGNORE_ERRORS_TAG "ignore-errors"
+#include "mm-modem-option-utils.c"
+
+/*****************************************************************************/
+
+static gint
+hso_get_cid (MMModemHso *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
-hso_call_control_done (MMSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
+auth_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemHso *self = MM_MODEM_HSO (info->modem);
+ MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self);
- if (error && !mm_callback_info_get_data (info, IGNORE_ERRORS_TAG))
- info->error = g_error_copy (error);
+ if (error) {
+ priv->auth_idx++;
+ if (auth_commands[priv->auth_idx]) {
+ /* Try the next auth command */
+ _internal_hso_modem_authenticate (self, info);
+ return;
+ } else
+ info->error = g_error_copy (error);
+ }
+ /* Reset to 0 so something gets tried the next connection */
+ priv->auth_idx = 0;
mm_callback_info_schedule (info);
}
-static guint32
-hso_get_cid (MMModemHso *self)
+static void
+_internal_hso_modem_authenticate (MMModemHso *self, MMCallbackInfo *info)
{
- guint32 cid;
+ MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self);
+ MMAtSerialPort *primary;
+ gint cid;
+ char *command;
- cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self));
- if (cid == 0)
- cid = 1;
+ primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
- return cid;
+ cid = hso_get_cid (self);
+ g_warn_if_fail (cid >= 0);
+
+ /* Both user and password are required; otherwise firmware returns an error */
+ if (!priv->username || !priv->password)
+ command = g_strdup_printf ("%s=%d,0", auth_commands[priv->auth_idx], cid);
+ else {
+ command = g_strdup_printf ("%s=%d,1,\"%s\",\"%s\"",
+ auth_commands[priv->auth_idx],
+ 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
-hso_call_control (MMModemHso *self,
- gboolean activate,
- gboolean ignore_errors,
- MMModemFn callback,
- gpointer user_data)
+void
+mm_hso_modem_authenticate (MMModemHso *self,
+ const char *username,
+ const char *password,
+ MMModemFn callback,
+ gpointer user_data)
{
+ MMModemHsoPrivate *priv;
MMCallbackInfo *info;
- char *command;
- MMSerialPort *primary;
+
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (MM_IS_MODEM_HSO (self));
+ g_return_if_fail (callback != NULL);
info = mm_callback_info_new (MM_MODEM (self), callback, user_data);
- mm_callback_info_set_data (info, IGNORE_ERRORS_TAG, GUINT_TO_POINTER (ignore_errors), NULL);
- command = g_strdup_printf ("AT_OWANCALL=%d,%d,1", hso_get_cid (self), activate ? 1 : 0);
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
- mm_serial_port_queue_command (primary, command, 3, hso_call_control_done, info);
- g_free (command);
+ priv = MM_MODEM_HSO_GET_PRIVATE (self);
+
+ g_free (priv->username);
+ priv->username = (username && strlen (username)) ? g_strdup (username) : NULL;
+
+ g_free (priv->password);
+ priv->password = (password && strlen (password)) ? g_strdup (password) : NULL;
+
+ _internal_hso_modem_authenticate (self, info);
}
+/*****************************************************************************/
+
static void
connect_pending_done (MMModemHso *self)
{
MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self);
+ GError *error = NULL;
if (priv->connect_pending_data) {
- mm_callback_info_schedule (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;
}
@@ -150,177 +213,175 @@ connect_pending_done (MMModemHso *self)
}
}
-static gboolean
-hso_connect_timed_out (gpointer data)
+static void
+connection_enabled (MMAtSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data)
{
- MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (data);
+ MMModemHso *self = MM_MODEM_HSO (user_data);
+ MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self);
+ char *str;
+
+ str = g_match_info_fetch (match_info, 2);
+ if (str[0] == '1')
+ connect_pending_done (self);
+ else if (str[0] == '3') {
+ MMCallbackInfo *info = priv->connect_pending_data;
- priv->connect_pending_data->error = g_error_new_literal (MM_SERIAL_ERROR,
- MM_SERIAL_RESPONSE_TIMEOUT,
- "Connection timed out");
- connect_pending_done (MM_MODEM_HSO (data));
+ if (info) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Call setup failed");
+ }
- return FALSE;
+ connect_pending_done (self);
+ } else if (str[0] == '0') {
+ /* FIXME: disconnected. do something when we have modem status signals */
+ }
+
+ g_free (str);
}
+/*****************************************************************************/
+
+#define IGNORE_ERRORS_TAG "ignore-errors"
+
static void
-hso_enabled (MMModem *modem,
- GError *error,
- gpointer user_data)
+hso_call_control_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- if (error) {
+ if (error && !mm_callback_info_get_data (info, IGNORE_ERRORS_TAG))
info->error = g_error_copy (error);
- mm_callback_info_schedule (info);
- } else {
- MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (modem);
- GSource *source;
- source = g_timeout_source_new_seconds (30);
- g_source_set_closure (source, g_cclosure_new_object (G_CALLBACK (hso_connect_timed_out), G_OBJECT (modem)));
- g_source_attach (source, NULL);
- priv->connect_pending_data = info;
- priv->connect_pending_id = g_source_get_id (source);
- g_source_unref (source);
- }
+ mm_callback_info_schedule (info);
}
static void
-clear_old_context (MMModem *modem,
- GError *error,
- gpointer user_data)
+hso_call_control (MMModemHso *self,
+ gboolean activate,
+ gboolean ignore_errors,
+ MMModemFn callback,
+ gpointer user_data)
{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMCallbackInfo *info;
+ char *command;
+ MMAtSerialPort *primary;
- if (error) {
- info->error = g_error_copy (error);
- mm_callback_info_schedule (info);
- } else {
- /* Success, activate the PDP context and start the data session */
- hso_call_control (MM_MODEM_HSO (modem), TRUE, FALSE, hso_enabled, info);
- }
+ info = mm_callback_info_new (MM_MODEM (self), callback, user_data);
+ mm_callback_info_set_data (info, IGNORE_ERRORS_TAG, GUINT_TO_POINTER (ignore_errors), NULL);
+
+ command = g_strdup_printf ("AT_OWANCALL=%d,%d,1", hso_get_cid (self), activate ? 1 : 0);
+ 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, command, 3, hso_call_control_done, info);
+ g_free (command);
}
static void
-auth_done (MMSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
+timeout_done (MMModem *modem,
+ GError *error,
+ gpointer user_data)
{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMModemHso *self = MM_MODEM_HSO (info->modem);
- MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self);
-
- if (error) {
- priv->auth_idx++;
- if (auth_commands[priv->auth_idx]) {
- /* Try the next auth command */
- _internal_hso_modem_authenticate (self, info);
- } else {
- /* Reset to 0 so that something gets tried for the next connection */
- priv->auth_idx = 0;
-
- info->error = g_error_copy (error);
- mm_callback_info_schedule (info);
- }
- } else {
- priv->auth_idx = 0;
-
- /* success, kill any existing connections first */
- hso_call_control (self, FALSE, TRUE, clear_old_context, info);
- }
+ if (modem)
+ connect_pending_done (MM_MODEM_HSO (modem));
}
-static void
-_internal_hso_modem_authenticate (MMModemHso *self, MMCallbackInfo *info)
+static gboolean
+hso_connect_timed_out (gpointer data)
{
+ MMModemHso *self = MM_MODEM_HSO (data);
MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self);
- MMSerialPort *primary;
- guint32 cid;
- char *command;
- const char *username, *password;
-
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
-
- cid = hso_get_cid (self);
-
- username = mm_callback_info_get_data (info, "username");
- password = mm_callback_info_get_data (info, "password");
+ MMCallbackInfo *info = priv->connect_pending_data;
- if (!username && !password)
- command = g_strdup_printf ("%s=%d,0", auth_commands[priv->auth_idx], cid);
- else {
- command = g_strdup_printf ("%s=%d,1,\"%s\",\"%s\"",
- auth_commands[priv->auth_idx],
- cid,
- password ? password : "",
- username ? username : "");
+ priv->connect_pending_id = 0;
+ if (info) {
+ info->error = g_error_new_literal (MM_SERIAL_ERROR,
+ MM_SERIAL_ERROR_RESPONSE_TIMEOUT,
+ "Connection timed out");
}
- mm_serial_port_queue_command (primary, command, 3, auth_done, info);
- g_free (command);
+ hso_call_control (self, FALSE, TRUE, timeout_done, self);
+ return FALSE;
}
-void
-mm_hso_modem_authenticate (MMModemHso *self,
- const char *username,
- const char *password,
- MMModemFn callback,
- gpointer user_data)
+static void
+hso_enabled (MMModem *modem,
+ GError *error,
+ gpointer user_data)
{
- MMCallbackInfo *info;
-
- g_return_if_fail (MM_IS_MODEM_HSO (self));
- g_return_if_fail (callback != NULL);
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ GError *tmp_error;
- info = mm_callback_info_new (MM_MODEM (self), callback, user_data);
- if (username)
- mm_callback_info_set_data (info, "username", g_strdup (username), g_free);
- if (password)
- mm_callback_info_set_data (info, "password", g_strdup (password), g_free);
+ tmp_error = mm_modem_check_removed (modem, error);
+ if (tmp_error) {
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (modem), tmp_error, info);
+ g_clear_error (&tmp_error);
+ } else {
+ MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (modem);
- _internal_hso_modem_authenticate (self, info);
+ priv->connect_pending_data = info;
+ priv->connect_pending_id = g_timeout_add_seconds (30, hso_connect_timed_out, modem);
+ }
}
-/*****************************************************************************/
-
static void
-enable_done (MMModem *modem, GError *error, gpointer user_data)
+old_context_clear_done (MMModem *modem,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ GError *tmp_error;
- mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info);
+ tmp_error = mm_modem_check_removed (modem, error);
+ if (tmp_error) {
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (modem), tmp_error, info);
+ g_clear_error (&tmp_error);
+ } else {
+ /* Success, activate the PDP context and start the data session */
+ hso_call_control (MM_MODEM_HSO (modem), TRUE, FALSE, hso_enabled, info);
+ }
}
static void
-parent_enable_done (MMModem *modem, GError *error, gpointer user_data)
+connect_auth_done (MMModem *modem,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMGenericGsm *self = MM_GENERIC_GSM (modem);
+ GError *tmp_error;
- if (error) {
- mm_generic_gsm_enable_complete (self, error, info);
- return;
+ tmp_error = mm_modem_check_removed (modem, error);
+ if (tmp_error) {
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (modem), tmp_error, info);
+ g_clear_error (&tmp_error);
+ } else {
+ /* Now connect; kill any existing connections first */
+ hso_call_control (MM_MODEM_HSO (modem), FALSE, TRUE, old_context_clear_done, info);
}
-
- /* HSO needs manual PIN checking */
- mm_generic_gsm_check_pin (self, enable_done, info);
}
static void
-enable (MMModem *modem, MMModemFn callback, gpointer user_data)
+do_connect (MMModem *modem,
+ const char *number,
+ MMModemFn callback,
+ gpointer user_data)
{
- MMModem *parent_modem_iface;
- MMCallbackInfo *info;
+ MMModemHso *self = MM_MODEM_HSO (modem);
+ MMCallbackInfo *auth_info, *connect_info;
- info = mm_callback_info_new (modem, callback, user_data);
- parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (info->modem));
- parent_modem_iface->enable (info->modem, parent_enable_done, info);
+ mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE);
+
+ connect_info = mm_callback_info_new (modem, callback, user_data);
+ auth_info = mm_callback_info_new (modem, connect_auth_done, connect_info);
+ _internal_hso_modem_authenticate (self, auth_info);
}
+/*****************************************************************************/
+
static void
parent_disable_done (MMModem *modem, GError *error, gpointer user_data)
{
@@ -345,32 +406,56 @@ disable_done (MMModem *modem,
}
static void
-disable (MMModem *modem,
- MMModemFn callback,
- gpointer user_data)
+unsolicited_disable_done (MMModem *modem,
+ GError *error,
+ gpointer user_data)
{
- MMCallbackInfo *info;
+ MMCallbackInfo *info = user_data;
- mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (modem));
+ /* Handle modem removal, but ignore other errors */
+ if (g_error_matches (error, MM_MODEM_ERROR, MM_MODEM_ERROR_REMOVED))
+ info->error = g_error_copy (error);
+ else if (!modem) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_REMOVED,
+ "The modem was removed.");
+ }
- info = mm_callback_info_new (modem, callback, user_data);
+ if (info->error) {
+ mm_callback_info_schedule (info);
+ return;
+ }
- /* Kill any existing connection */
- hso_call_control (MM_MODEM_HSO (modem), FALSE, TRUE, disable_done, info);
+ /* Otherwise, kill any existing connection */
+ if (mm_generic_gsm_get_cid (MM_GENERIC_GSM (modem)) >= 0)
+ hso_call_control (MM_MODEM_HSO (modem), FALSE, TRUE, disable_done, info);
+ else
+ disable_done (modem, NULL, info);
}
static void
-do_connect (MMModem *modem,
- const char *number,
- MMModemFn callback,
- gpointer user_data)
+disable (MMModem *modem,
+ MMModemFn callback,
+ gpointer user_data)
{
+ MMModemHso *self = MM_MODEM_HSO (modem);
+ MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self);
MMCallbackInfo *info;
+ mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (modem));
+
+ g_free (priv->username);
+ priv->username = NULL;
+ g_free (priv->password);
+ priv->password = NULL;
+
info = mm_callback_info_new (modem, callback, user_data);
- mm_callback_info_schedule (info);
+
+ /* Turn off unsolicited messages so they don't pile up in the modem */
+ option_change_unsolicited_messages (MM_GENERIC_GSM (modem), FALSE, unsolicited_disable_done, info);
}
+/*****************************************************************************/
static void
free_dns_array (gpointer data)
@@ -390,7 +475,7 @@ ip4_config_invoke (MMCallbackInfo *info)
}
static void
-get_ip4_config_done (MMSerialPort *port,
+get_ip4_config_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -400,7 +485,7 @@ get_ip4_config_done (MMSerialPort *port,
GArray *dns_array;
int i;
guint32 tmp;
- guint cid;
+ gint cid;
if (error) {
info->error = g_error_copy (error);
@@ -421,7 +506,7 @@ get_ip4_config_done (MMSerialPort *port,
errno = 0;
num = strtol (*iter, NULL, 10);
- if (errno != 0 || num < 0 || (guint) num != cid) {
+ if (errno != 0 || num < 0 || (gint) num != cid) {
info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
"Unknown CID in OWANDATA response ("
"got %d, expected %d)", (guint) num, cid);
@@ -453,28 +538,61 @@ get_ip4_config (MMModem *modem,
{
MMCallbackInfo *info;
char *command;
- MMSerialPort *primary;
+ MMAtSerialPort *primary;
info = mm_callback_info_new_full (modem, ip4_config_invoke, G_CALLBACK (callback), user_data);
command = g_strdup_printf ("AT_OWANDATA=%d", hso_get_cid (MM_MODEM_HSO (modem)));
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
g_assert (primary);
- mm_serial_port_queue_command (primary, command, 3, get_ip4_config_done, info);
+ mm_at_serial_port_queue_command (primary, command, 3, get_ip4_config_done, info);
g_free (command);
}
+/*****************************************************************************/
+
static void
-disconnect (MMModem *modem,
- MMModemFn callback,
- gpointer user_data)
+disconnect_owancall_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ mm_callback_info_schedule ((MMCallbackInfo *) user_data);
+}
+
+static void
+do_disconnect (MMGenericGsm *gsm,
+ gint cid,
+ MMModemFn callback,
+ gpointer user_data)
{
MMCallbackInfo *info;
- MMSerialPort *primary;
+ MMAtSerialPort *primary;
+ char *command;
- info = mm_callback_info_new (modem, callback, user_data);
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ 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);
- mm_serial_port_queue_command (primary, "AT_OWANCALL=1,0,0", 3, NULL, info);
+
+ command = g_strdup_printf ("AT_OWANCALL=%d,0,0", cid);
+ mm_at_serial_port_queue_command (primary, command, 3, disconnect_owancall_done, info);
+ g_free (command);
+}
+
+/*****************************************************************************/
+
+static void
+real_do_enable_power_up_done (MMGenericGsm *gsm,
+ GString *response,
+ GError *error,
+ MMCallbackInfo *info)
+{
+ /* Enable Option unsolicited messages */
+ if (gsm && !error)
+ option_change_unsolicited_messages (gsm, TRUE, NULL, NULL);
+
+ /* Chain up to parent */
+ MM_GENERIC_GSM_CLASS (mm_modem_hso_parent_class)->do_enable_power_up_done (gsm, response, error, info);
}
/*****************************************************************************/
@@ -507,47 +625,11 @@ impl_hso_authenticate (MMModemHso *self,
mm_hso_modem_authenticate (self, username, password, impl_hso_auth_done, context);
}
-static void
-connection_enabled (MMSerialPort *port,
- GMatchInfo *info,
- gpointer user_data)
-{
- MMModemHso *self = MM_MODEM_HSO (user_data);
- MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self);
- char *str;
-
- str = g_match_info_fetch (info, 2);
- if (str[0] == '1')
- connect_pending_done (self);
- else if (str[0] == '3') {
- MMCallbackInfo *cb_info = priv->connect_pending_data;
-
- if (cb_info)
- cb_info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Call setup failed");
-
- connect_pending_done (self);
- } else if (str[0] == '0')
- /* FIXME: disconnected. do something when we have modem status signals */
- ;
-
- g_free (str);
-}
-
/*****************************************************************************/
-/* MMModemSimple interface */
-
-typedef enum {
- SIMPLE_STATE_BEGIN = 0,
- SIMPLE_STATE_PARENT_CONNECT,
- SIMPLE_STATE_AUTHENTICATE,
- SIMPLE_STATE_DONE
-} SimpleState;
static const char *
-simple_get_string_property (MMCallbackInfo *info, const char *name, GError **error)
+hso_simple_get_string_property (GHashTable *properties, const char *name, GError **error)
{
- GHashTable *properties = (GHashTable *) mm_callback_info_get_data (info, "simple-connect-properties");
GValue *value;
value = (GValue *) g_hash_table_lookup (properties, name);
@@ -565,60 +647,47 @@ simple_get_string_property (MMCallbackInfo *info, const char *name, GError **err
}
static void
-simple_state_machine (MMModem *modem, GError *error, gpointer user_data)
+simple_connect (MMModemSimple *simple,
+ GHashTable *properties,
+ MMModemFn callback,
+ gpointer user_data)
{
+ MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (simple);
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMModemSimple *parent_iface;
- const char *username;
- const char *password;
- GHashTable *properties = (GHashTable *) mm_callback_info_get_data (info, "simple-connect-properties");
- SimpleState state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "simple-connect-state"));
-
- if (error) {
- info->error = g_error_copy (error);
- goto out;
- }
- switch (state) {
- case SIMPLE_STATE_BEGIN:
- state = SIMPLE_STATE_PARENT_CONNECT;
- parent_iface = g_type_interface_peek_parent (MM_MODEM_SIMPLE_GET_INTERFACE (modem));
- parent_iface->connect (MM_MODEM_SIMPLE (modem), properties, simple_state_machine, info);
- break;
- case SIMPLE_STATE_PARENT_CONNECT:
- state = SIMPLE_STATE_AUTHENTICATE;
- username = simple_get_string_property (info, "username", &info->error);
- password = simple_get_string_property (info, "password", &info->error);
- mm_hso_modem_authenticate (MM_MODEM_HSO (modem), username, password, simple_state_machine, info);
- break;
- case SIMPLE_STATE_AUTHENTICATE:
- state = SIMPLE_STATE_DONE;
- break;
- default:
- break;
- }
+ priv->username = g_strdup (hso_simple_get_string_property (properties, "username", NULL));
+ priv->password = g_strdup (hso_simple_get_string_property (properties, "password", NULL));
- out:
- if (info->error || state == SIMPLE_STATE_DONE)
- mm_callback_info_schedule (info);
- else
- mm_callback_info_set_data (info, "simple-connect-state", GUINT_TO_POINTER (state), NULL);
+ 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
-simple_connect (MMModemSimple *simple,
- GHashTable *properties,
- MMModemFn callback,
- gpointer user_data)
+get_allowed_mode (MMGenericGsm *gsm,
+ MMModemUIntFn callback,
+ gpointer user_data)
{
- MMCallbackInfo *info;
+ option_get_allowed_mode (gsm, callback, user_data);
+}
- info = mm_callback_info_new (MM_MODEM (simple), callback, user_data);
- mm_callback_info_set_data (info, "simple-connect-properties",
- g_hash_table_ref (properties),
- (GDestroyNotify) g_hash_table_unref);
+static void
+set_allowed_mode (MMGenericGsm *gsm,
+ MMModemGsmAllowedMode mode,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ option_set_allowed_mode (gsm, mode, callback, user_data);
+}
- simple_state_machine (MM_MODEM (simple), NULL, info);
+static void
+get_access_technology (MMGenericGsm *gsm,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ option_get_access_technology (gsm, callback, user_data);
}
/*****************************************************************************/
@@ -676,17 +745,20 @@ grab_port (MMModem *modem,
if (!port)
goto out;
- if (MM_IS_SERIAL_PORT (port)) {
+ if (MM_IS_AT_SERIAL_PORT (port)) {
g_object_set (G_OBJECT (port), MM_SERIAL_PORT_SEND_DELAY, (guint64) 10000, NULL);
if (ptype == MM_PORT_TYPE_PRIMARY) {
GRegex *regex;
- mm_generic_gsm_set_unsolicited_registration (gsm, TRUE);
-
regex = g_regex_new ("_OWANCALL: (\\d),\\s*(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, connection_enabled, modem, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, connection_enabled, modem, 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);
}
+ option_register_unsolicted_handlers (gsm, MM_AT_SERIAL_PORT (port));
}
out:
@@ -712,19 +784,23 @@ modem_simple_init (MMModemSimple *class)
static void
modem_init (MMModem *modem_class)
{
- modem_class->enable = enable;
modem_class->disable = disable;
modem_class->connect = do_connect;
modem_class->get_ip4_config = get_ip4_config;
- modem_class->disconnect = disconnect;
modem_class->grab_port = grab_port;
}
static void
finalize (GObject *object)
{
+ MMModemHso *self = MM_MODEM_HSO (object);
+ MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self);
+
/* Clear the pending connection if necessary */
- connect_pending_done (MM_MODEM_HSO (object));
+ connect_pending_done (self);
+
+ g_free (priv->username);
+ g_free (priv->password);
G_OBJECT_CLASS (mm_modem_hso_parent_class)->finalize (object);
}
@@ -733,11 +809,17 @@ static void
mm_modem_hso_class_init (MMModemHsoClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
mm_modem_hso_parent_class = g_type_class_peek_parent (klass);
g_type_class_add_private (object_class, sizeof (MMModemHsoPrivate));
/* Virtual methods */
object_class->finalize = finalize;
+ gsm_class->do_disconnect = do_disconnect;
+ gsm_class->do_enable_power_up_done = real_do_enable_power_up_done;
+ 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-huawei-cdma.c b/plugins/mm-modem-huawei-cdma.c
index 3b63a48..523578f 100644
--- a/plugins/mm-modem-huawei-cdma.c
+++ b/plugins/mm-modem-huawei-cdma.c
@@ -41,16 +41,26 @@ mm_modem_huawei_cdma_new (const char *device,
gboolean evdo_rev0,
gboolean evdo_revA)
{
+ gboolean try_css = TRUE;
+
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
g_return_val_if_fail (plugin != NULL, NULL);
+ /* Don't use AT+CSS on EVDO-capable hardware for determining registration
+ * status, because often the device will have only an EVDO connection and
+ * AT+CSS won't necessarily report EVDO registration status, only 1X.
+ */
+ if (evdo_rev0 || evdo_revA)
+ try_css = FALSE;
+
return MM_MODEM (g_object_new (MM_TYPE_MODEM_HUAWEI_CDMA,
MM_MODEM_MASTER_DEVICE, device,
MM_MODEM_DRIVER, driver,
MM_MODEM_PLUGIN, plugin,
MM_GENERIC_CDMA_EVDO_REV0, evdo_rev0,
MM_GENERIC_CDMA_EVDO_REVA, evdo_revA,
+ MM_GENERIC_CDMA_REGISTRATION_TRY_CSS, try_css,
NULL));
}
@@ -72,7 +82,7 @@ parse_quality (const char *str, const char *detail)
}
static void
-handle_1x_quality_change (MMSerialPort *port,
+handle_1x_quality_change (MMAtSerialPort *port,
GMatchInfo *match_info,
gpointer user_data)
{
@@ -89,9 +99,9 @@ handle_1x_quality_change (MMSerialPort *port,
}
static void
-handle_evdo_quality_change (MMSerialPort *port,
- GMatchInfo *match_info,
- gpointer user_data)
+handle_evdo_quality_change (MMAtSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data)
{
MMModemHuaweiCdma *self = MM_MODEM_HUAWEI_CDMA (user_data);
char *str;
@@ -142,7 +152,7 @@ uint_from_match_item (GMatchInfo *match_info, guint32 num, guint32 *val)
}
static void
-sysinfo_done (MMSerialPort *port,
+sysinfo_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -151,12 +161,10 @@ sysinfo_done (MMSerialPort *port,
GRegex *r;
GMatchInfo *match_info;
const char *reply;
- gboolean success = FALSE;
if (error) {
- info->error = g_error_copy (error);
- mm_callback_info_schedule (info);
- return;
+ /* Leave superclass' reg state alone if AT^SYSINFO isn't supported */
+ goto done;
}
reply = strip_response (response->str, "^SYSINFO:");
@@ -165,9 +173,7 @@ sysinfo_done (MMSerialPort *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) {
- info->error = g_error_new_literal (MM_MODEM_ERROR,
- MM_MODEM_ERROR_GENERAL,
- "Could not parse sysinfo results (regex creation failed).");
+ g_warning ("Huawei(%s): ^SYSINFO parse regex creation failed.", __func__);
goto done;
}
@@ -207,48 +213,35 @@ sysinfo_done (MMSerialPort *port,
/* Say we're registered to something even though sysmode parsing failed */
mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state);
}
- success = TRUE;
- }
+ } else
+ g_warning ("Huawei(%s): failed to parse ^SYSINFO response.", __func__);
-done:
g_match_info_free (match_info);
g_regex_unref (r);
-
- if (!success && !info->error) {
- info->error = g_error_new_literal (MM_MODEM_ERROR,
- MM_MODEM_ERROR_GENERAL,
- "Could not parse sysinfo results.");
- }
+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;
- MMSerialPort *primary, *secondary, *port;
-
- port = primary = mm_generic_cdma_get_port (cdma, MM_PORT_TYPE_PRIMARY);
- secondary = mm_generic_cdma_get_port (cdma, MM_PORT_TYPE_SECONDARY);
+ MMAtSerialPort *port;
- info = mm_generic_cdma_query_reg_state_callback_info_new (cdma, callback, user_data);
+ info = mm_generic_cdma_query_reg_state_callback_info_new (cdma, cur_cdma_state, cur_evdo_state, callback, user_data);
- if (mm_port_get_connected (MM_PORT (primary))) {
- if (!secondary) {
- info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_CONNECTED,
- "Cannot get query registration state while connected");
- mm_callback_info_schedule (info);
- return;
- }
-
- /* Use secondary port if primary is connected */
- port = secondary;
+ port = mm_generic_cdma_get_best_at_port (cdma, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
}
- mm_serial_port_queue_command (port, "^SYSINFO", 3, sysinfo_done, info);
+ mm_at_serial_port_queue_command (port, "^SYSINFO", 3, sysinfo_done, info);
}
/*****************************************************************************/
@@ -265,14 +258,14 @@ grab_port (MMModem *modem,
GRegex *regex;
port = mm_generic_cdma_grab_port (MM_GENERIC_CDMA (modem), subsys, name, suggested_type, user_data, error);
- if (port && MM_IS_SERIAL_PORT (port)) {
+ if (port && MM_IS_AT_SERIAL_PORT (port)) {
gboolean evdo0 = FALSE, evdoA = FALSE;
g_object_set (G_OBJECT (port), MM_PORT_CARRIER_DETECT, FALSE, NULL);
/* 1x signal level */
regex = g_regex_new ("\\r\\n\\^RSSILVL:(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, handle_1x_quality_change, modem, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, handle_1x_quality_change, modem, NULL);
g_regex_unref (regex);
g_object_get (G_OBJECT (modem),
@@ -283,7 +276,7 @@ grab_port (MMModem *modem,
if (evdo0 || evdoA) {
/* EVDO signal level */
regex = g_regex_new ("\\r\\n\\^HRSSILVL:(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, handle_evdo_quality_change, modem, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, handle_evdo_quality_change, modem, NULL);
g_regex_unref (regex);
}
}
diff --git a/plugins/mm-modem-huawei-gsm.c b/plugins/mm-modem-huawei-gsm.c
index d450f25..5123e7f 100644
--- a/plugins/mm-modem-huawei-gsm.c
+++ b/plugins/mm-modem-huawei-gsm.c
@@ -11,38 +11,40 @@
* 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <errno.h>
#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
#include <gudev/gudev.h>
#include "mm-modem-huawei-gsm.h"
#include "mm-modem-gsm-network.h"
+#include "mm-modem-gsm-card.h"
#include "mm-errors.h"
#include "mm-callback-info.h"
-#include "mm-serial-port.h"
+#include "mm-at-serial-port.h"
#include "mm-serial-parsers.h"
static void modem_init (MMModem *modem_class);
static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class);
+static void modem_gsm_card_init (MMModemGsmCard *gsm_card_class);
G_DEFINE_TYPE_EXTENDED (MMModemHuaweiGsm, mm_modem_huawei_gsm, MM_TYPE_GENERIC_GSM, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)
- G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_NETWORK, modem_gsm_network_init))
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_NETWORK, modem_gsm_network_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_CARD, modem_gsm_card_init))
#define MM_MODEM_HUAWEI_GSM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_HUAWEI_GSM, MMModemHuaweiGsmPrivate))
typedef struct {
/* Cached state */
- guint signal_quality;
- MMModemGsmMode mode;
- MMModemGsmBand band;
+ guint32 band;
} MMModemHuaweiGsmPrivate;
MMModem *
@@ -61,6 +63,61 @@ mm_modem_huawei_gsm_new (const char *device,
NULL));
}
+/*****************************************************************************/
+
+typedef struct {
+ MMModemGsmBand mm;
+ guint32 huawei;
+} BandTable;
+
+static BandTable bands[] = {
+ /* Sort 3G first since it's preferred */
+ { MM_MODEM_GSM_BAND_U2100, 0x00400000 },
+ { MM_MODEM_GSM_BAND_U1900, 0x00800000 },
+ { MM_MODEM_GSM_BAND_U850, 0x04000000 },
+ { MM_MODEM_GSM_BAND_U900, 0x00020000 },
+ { MM_MODEM_GSM_BAND_G850, 0x00080000 },
+ /* 2G second */
+ { MM_MODEM_GSM_BAND_DCS, 0x00000080 },
+ { MM_MODEM_GSM_BAND_EGSM, 0x00000300 }, /* 0x100 = Extended GSM, 0x200 = Primary GSM */
+ { MM_MODEM_GSM_BAND_PCS, 0x00200000 },
+ /* And ANY last since it's most inclusive */
+ { MM_MODEM_GSM_BAND_ANY, 0x3FFFFFFF },
+};
+
+static gboolean
+band_mm_to_huawei (MMModemGsmBand band, guint32 *out_huawei)
+{
+ int i;
+
+ for (i = 0; i < sizeof (bands) / sizeof (BandTable); i++) {
+ if (bands[i].mm == band) {
+ *out_huawei = bands[i].huawei;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static gboolean
+band_huawei_to_mm (guint32 huawei, MMModemGsmBand *out_mm)
+{
+ int i;
+
+ for (i = 0; i < sizeof (bands) / sizeof (BandTable); i++) {
+ /* The dongle returns a bitfield, but since we don't support that
+ * yet in MM, take the "best" band and return it.
+ */
+ if (bands[i].huawei & huawei) {
+ *out_mm = bands[i].mm;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*****************************************************************************/
+
static gboolean
parse_syscfg (MMModemHuaweiGsm *self,
const char *reply,
@@ -68,31 +125,31 @@ parse_syscfg (MMModemHuaweiGsm *self,
int *mode_b,
guint32 *band,
int *unknown1,
- int *unknown2)
+ int *unknown2,
+ MMModemGsmAllowedMode *out_mode)
{
if (reply == NULL || strncmp (reply, "^SYSCFG:", 8))
return FALSE;
if (sscanf (reply + 8, "%d,%d,%x,%d,%d", mode_a, mode_b, band, unknown1, unknown2)) {
MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (self);
-
+ MMModemGsmAllowedMode new_mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+
/* Network mode */
if (*mode_a == 2 && *mode_b == 1)
- priv->mode = MM_MODEM_GSM_MODE_2G_PREFERRED;
+ new_mode = MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED;
else if (*mode_a == 2 && *mode_b == 2)
- priv->mode = MM_MODEM_GSM_MODE_3G_PREFERRED;
+ new_mode = MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED;
else if (*mode_a == 13 && *mode_b == 1)
- priv->mode = MM_MODEM_GSM_MODE_2G_ONLY;
+ new_mode = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY;
else if (*mode_a == 14 && *mode_b == 2)
- priv->mode = MM_MODEM_GSM_MODE_3G_ONLY;
+ new_mode = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY;
+
+ if (out_mode)
+ *out_mode = new_mode;
/* Band */
- if (*band == 0x3FFFFFFF)
- priv->band = MM_MODEM_GSM_BAND_ANY;
- else if (*band == 0x400380)
- priv->band = MM_MODEM_GSM_BAND_DCS;
- else if (*band == 0x200000)
- priv->band = MM_MODEM_GSM_BAND_PCS;
+ priv->band = *band;
return TRUE;
}
@@ -101,165 +158,108 @@ parse_syscfg (MMModemHuaweiGsm *self,
}
static void
-set_network_mode_done (MMSerialPort *port,
+set_allowed_mode_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMModemHuaweiGsm *self = MM_MODEM_HUAWEI_GSM (info->modem);
- MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (self);
if (error)
info->error = g_error_copy (error);
- else
- /* Success, cache the value */
- priv->mode = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "mode"));
mm_callback_info_schedule (info);
}
static void
-set_network_mode_get_done (MMSerialPort *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);
- } else {
- int a, b, u1, u2;
- guint32 band;
-
- if (parse_syscfg (MM_MODEM_HUAWEI_GSM (info->modem), response->str, &a, &b, &band, &u1, &u2)) {
- char *command;
-
- switch (GPOINTER_TO_UINT (mm_callback_info_get_data (info, "mode"))) {
- case MM_MODEM_GSM_MODE_ANY:
- a = 2;
- b = 0;
- break;
- case MM_MODEM_GSM_MODE_GPRS:
- case MM_MODEM_GSM_MODE_EDGE:
- case MM_MODEM_GSM_MODE_2G_ONLY:
- a = 13;
- b = 1;
- break;
- case MM_MODEM_GSM_MODE_UMTS:
- case MM_MODEM_GSM_MODE_HSDPA:
- case MM_MODEM_GSM_MODE_HSUPA:
- case MM_MODEM_GSM_MODE_HSPA:
- case MM_MODEM_GSM_MODE_3G_ONLY:
- a = 14;
- b = 2;
- break;
- case MM_MODEM_GSM_MODE_2G_PREFERRED:
- a = 2;
- b = 1;
- break;
- case MM_MODEM_GSM_MODE_3G_PREFERRED:
- a = 2;
- b = 2;
- break;
- default:
- break;
- }
-
- command = g_strdup_printf ("AT^SYSCFG=%d,%d,%X,%d,%d", a, b, band, u1, u2);
- mm_serial_port_queue_command (port, command, 3, set_network_mode_done, info);
- g_free (command);
- }
- }
-}
-
-static void
-set_network_mode (MMModemGsmNetwork *modem,
- MMModemGsmMode mode,
+set_allowed_mode (MMGenericGsm *gsm,
+ MMModemGsmAllowedMode mode,
MMModemFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
- MMSerialPort *primary;
+ MMAtSerialPort *port;
+ int a, b;
+ char *command;
- info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
+ info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data);
- switch (mode) {
- case MM_MODEM_GSM_MODE_ANY:
- case MM_MODEM_GSM_MODE_GPRS:
- case MM_MODEM_GSM_MODE_EDGE:
- case MM_MODEM_GSM_MODE_UMTS:
- case MM_MODEM_GSM_MODE_HSDPA:
- case MM_MODEM_GSM_MODE_HSUPA:
- case MM_MODEM_GSM_MODE_HSPA:
- case MM_MODEM_GSM_MODE_2G_PREFERRED:
- case MM_MODEM_GSM_MODE_3G_PREFERRED:
- case MM_MODEM_GSM_MODE_2G_ONLY:
- case MM_MODEM_GSM_MODE_3G_ONLY:
- /* Allowed values */
- mm_callback_info_set_data (info, "mode", GUINT_TO_POINTER (mode), NULL);
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
- mm_serial_port_queue_command (primary, "AT^SYSCFG?", 3, set_network_mode_get_done, info);
+ 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:
+ a = 13;
+ b = 1;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY:
+ a = 14;
+ b = 2;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED:
+ a = 2;
+ b = 1;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED:
+ a = 2;
+ b = 2;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_ANY:
default:
- info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Invalid mode.");
+ a = 2;
+ b = 0;
break;
}
- mm_callback_info_schedule (info);
+ command = g_strdup_printf ("AT^SYSCFG=%d,%d,40000000,2,4", a, b);
+ mm_at_serial_port_queue_command (port, command, 3, set_allowed_mode_done, info);
+ g_free (command);
}
static void
-get_network_mode_done (MMSerialPort *port,
+get_allowed_mode_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMModemHuaweiGsm *self = MM_MODEM_HUAWEI_GSM (info->modem);
- MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (self);
int mode_a, mode_b, u1, u2;
guint32 band;
+ MMModemGsmAllowedMode mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
if (error)
info->error = g_error_copy (error);
- else if (parse_syscfg (self, response->str, &mode_a, &mode_b, &band, &u1, &u2))
- mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->mode), NULL);
+ else if (parse_syscfg (self, response->str, &mode_a, &mode_b, &band, &u1, &u2, &mode))
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mode), NULL);
mm_callback_info_schedule (info);
}
static void
-get_network_mode (MMModemGsmNetwork *modem,
+get_allowed_mode (MMGenericGsm *gsm,
MMModemUIntFn callback,
gpointer user_data)
{
- MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (modem);
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
- if (priv->mode != MM_MODEM_GSM_MODE_ANY) {
- /* have cached mode (from an unsolicited message). Use that */
- MMCallbackInfo *info;
+ info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data);
- info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->mode), NULL);
+ port = mm_generic_gsm_get_best_at_port (gsm, &info->error);
+ if (!port) {
mm_callback_info_schedule (info);
- } else {
- /* Get it from modem */
- MMCallbackInfo *info;
- MMSerialPort *primary;
-
- info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
- mm_serial_port_queue_command (primary, "AT^SYSCFG?", 3, get_network_mode_done, info);
+ return;
}
+
+ mm_at_serial_port_queue_command (port, "AT^SYSCFG?", 3, get_allowed_mode_done, info);
}
static void
-set_band_done (MMSerialPort *port,
+set_band_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -270,108 +270,63 @@ set_band_done (MMSerialPort *port,
if (error)
info->error = g_error_copy (error);
- else
+ else {
/* Success, cache the value */
priv->band = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "band"));
+ }
mm_callback_info_schedule (info);
}
static void
-set_band_get_done (MMSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMModemHuaweiGsm *self = MM_MODEM_HUAWEI_GSM (info->modem);
-
- if (error) {
- info->error = g_error_copy (error);
- mm_callback_info_schedule (info);
- } else {
- int a, b, u1, u2;
- guint32 band;
-
- if (parse_syscfg (self, response->str, &a, &b, &band, &u1, &u2)) {
- char *command;
-
- switch (GPOINTER_TO_UINT (mm_callback_info_get_data (info, "band"))) {
- case MM_MODEM_GSM_BAND_ANY:
- band = 0x3FFFFFFF;
- break;
- case MM_MODEM_GSM_BAND_EGSM:
- band = 0x100;
- break;
- case MM_MODEM_GSM_BAND_DCS:
- band = 0x80;
- break;
- case MM_MODEM_GSM_BAND_U2100:
- band = 0x400000;
- break;
- case MM_MODEM_GSM_BAND_PCS:
- band = 0x200000;
- break;
- case MM_MODEM_GSM_BAND_G850:
- band = 0x80000;
- break;
- default:
- break;
- }
-
- command = g_strdup_printf ("AT^SYSCFG=%d,%d,%X,%d,%d", a, b, band, u1, u2);
- mm_serial_port_queue_command (port, command, 3, set_band_done, info);
- g_free (command);
- }
- }
-}
-
-static void
set_band (MMModemGsmNetwork *modem,
MMModemGsmBand band,
MMModemFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
- MMSerialPort *primary;
+ MMAtSerialPort *port;
+ char *command;
+ guint32 huawei_band = 0x3FFFFFFF;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
- switch (band) {
- case MM_MODEM_GSM_BAND_ANY:
- case MM_MODEM_GSM_BAND_EGSM:
- case MM_MODEM_GSM_BAND_DCS:
- case MM_MODEM_GSM_BAND_U2100:
- case MM_MODEM_GSM_BAND_PCS:
- mm_callback_info_set_data (info, "band", GUINT_TO_POINTER (band), NULL);
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
- mm_serial_port_queue_command (primary, "AT^SYSCFG?", 3, set_band_get_done, info);
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
return;
- default:
- info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Invalid band.");
- break;
}
- mm_callback_info_schedule (info);
+ if (!band_mm_to_huawei (band, &huawei_band)) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Invalid band.");
+ mm_callback_info_schedule (info);
+ } else {
+ mm_callback_info_set_data (info, "band", GUINT_TO_POINTER (huawei_band), NULL);
+ command = g_strdup_printf ("AT^SYSCFG=16,3,%X,2,4", huawei_band);
+ mm_at_serial_port_queue_command (port, command, 3, set_band_done, info);
+ g_free (command);
+ }
}
static void
-get_band_done (MMSerialPort *port,
+get_band_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMModemHuaweiGsm *self = MM_MODEM_HUAWEI_GSM (info->modem);
- MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (self);
int mode_a, mode_b, u1, u2;
guint32 band;
if (error)
info->error = g_error_copy (error);
- else if (parse_syscfg (self, response->str, &mode_a, &mode_b, &band, &u1, &u2))
- mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->band), NULL);
+ else if (parse_syscfg (self, response->str, &mode_a, &mode_b, &band, &u1, &u2, NULL)) {
+ MMModemGsmBand mm_band = MM_MODEM_GSM_BAND_ANY;
+
+ band_huawei_to_mm (band, &mm_band);
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mm_band), NULL);
+ }
mm_callback_info_schedule (info);
}
@@ -382,84 +337,289 @@ get_band (MMModemGsmNetwork *modem,
gpointer user_data)
{
MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (modem);
- MMSerialPort *primary;
+ MMAtSerialPort *port;
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- if (priv->band != MM_MODEM_GSM_BAND_ANY) {
- /* have cached mode (from an unsolicited message). Use that */
- MMCallbackInfo *info;
+ /* Prefer cached band from unsolicited messages if we have it */
+ if (priv->band != 0) {
+ MMModemGsmBand mm_band = MM_MODEM_GSM_BAND_ANY;
- info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->band), NULL);
+ band_huawei_to_mm (priv->band, &mm_band);
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mm_band), NULL);
mm_callback_info_schedule (info);
- } else {
- /* Get it from modem */
- MMCallbackInfo *info;
+ return;
+ }
- info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
- mm_serial_port_queue_command (primary, "AT^SYSCFG?", 3, get_band_done, info);
+ /* Otherwise ask the modem */
+ 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, "AT^SYSCFG?", 3, get_band_done, info);
}
static void
-get_signal_quality (MMModemGsmNetwork *modem,
+get_act_request_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ GRegex *r = NULL;
+ GMatchInfo *match_info = NULL;
+ char *str;
+ int srv_stat = 0;
+
+ if (error) {
+ info->error = g_error_copy (error);
+ goto done;
+ }
+
+ /* Can't just use \d here since sometimes you get "^SYSINFO:2,1,0,3,1,,3" */
+ r = g_regex_new ("\\^SYSINFO:\\s*(\\d?),(\\d?),(\\d?),(\\d?),(\\d?),(\\d?),(\\d?)$", G_REGEX_UNGREEDY, 0, NULL);
+ if (!r) {
+ g_set_error_literal (&info->error,
+ MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Could not parse ^SYSINFO results.");
+ goto done;
+ }
+
+ if (!g_regex_match_full (r, response->str, response->len, 0, 0, &match_info, &info->error)) {
+ g_set_error_literal (&info->error,
+ MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Could not parse ^SYSINFO results.");
+ goto done;
+ }
+
+ str = g_match_info_fetch (match_info, 1);
+ if (str && strlen (str))
+ srv_stat = atoi (str);
+ g_free (str);
+
+ 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;
+ }
+ g_free (str);
+ }
+
+done:
+ if (match_info)
+ g_match_info_free (match_info);
+ if (r)
+ g_regex_unref (r);
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (act), NULL);
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_access_technology (MMGenericGsm *modem,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMAtSerialPort *port;
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (modem, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (port, "^SYSINFO", 3, get_act_request_done, info);
+}
+
+/*****************************************************************************/
+
+static gboolean
+parse_num (const char *str, guint32 *out_num, guint32 min, guint32 max)
+{
+ unsigned long int tmp;
+
+ if (!str || !strlen (str))
+ return FALSE;
+
+ errno = 0;
+ tmp = strtoul (str, NULL, 10);
+ if (errno != 0 || tmp < min || tmp > max)
+ return FALSE;
+ *out_num = (guint32) tmp;
+ return TRUE;
+}
+
+static void
+send_huawei_cpin_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ GRegex *r = NULL;
+ GMatchInfo *match_info = NULL;
+ const char *pin_type;
+ guint32 attempts_left = 0;
+ char *str = NULL;
+ guint32 num = 0;
+
+ if (error) {
+ info->error = g_error_copy (error);
+ goto done;
+ }
+
+ pin_type = mm_callback_info_get_data (info, "pin_type");
+
+ r = g_regex_new ("\\^CPIN:\\s*([^,]+),[^,]*,(\\d+),(\\d+),(\\d+),(\\d+)", G_REGEX_UNGREEDY, 0, NULL);
+ if (!r) {
+ g_set_error_literal (&info->error,
+ MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Could not parse ^CPIN results (error creating regex).");
+ goto done;
+ }
+
+ if (!g_regex_match_full (r, response->str, response->len, 0, 0, &match_info, &info->error)) {
+ g_set_error_literal (&info->error,
+ MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Could not parse ^CPIN results (match failed).");
+ goto done;
+ }
+
+ if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PUK))
+ num = 2;
+ else if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PIN))
+ num = 3;
+ else if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PUK2))
+ num = 4;
+ else if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PIN2))
+ num = 5;
+ else {
+ g_debug ("%s: unhandled pin type '%s'", __func__, pin_type);
+
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Unhandled PIN type");
+ }
+
+ if (num > 0) {
+ gboolean success = FALSE;
+
+ str = g_match_info_fetch (match_info, num);
+ if (str) {
+ success = parse_num (str, &attempts_left, 0, 10);
+ g_free (str);
+ }
+
+ if (!success) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Could not parse ^CPIN results (missing or invalid match info).");
+ }
+ }
+
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (attempts_left), NULL);
+
+ g_match_info_free (match_info);
+
+done:
+ if (r)
+ g_regex_unref (r);
+ mm_serial_port_close (MM_SERIAL_PORT (port));
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_unlock_retries (MMModemGsmCard *modem,
+ const char *pin_type,
MMModemUIntFn callback,
gpointer user_data)
{
- MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (modem);
+ MMAtSerialPort *port;
+ char *command;
+ MMCallbackInfo *info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- if (priv->signal_quality) {
- /* have cached signal quality (from an unsolicited message). Use that */
- MMCallbackInfo *info;
+ g_debug ("%s: pin type '%s'", __func__, pin_type);
- info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->signal_quality), NULL);
+ /* 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_callback_info_schedule (info);
- } else {
- /* Use the generic implementation */
- MMModemGsmNetwork *parent_gsm_network_iface;
+ return;
+ }
- parent_gsm_network_iface = g_type_interface_peek_parent (MM_MODEM_GSM_NETWORK_GET_INTERFACE (modem));
- parent_gsm_network_iface->get_signal_quality (modem, callback, user_data);
+ /* Modem may not be enabled yet, which sometimes can't be done until
+ * the device has been unlocked. In this case we have to open the port
+ * ourselves.
+ */
+ if (!mm_serial_port_open (MM_SERIAL_PORT (port), &info->error)) {
+ mm_callback_info_schedule (info);
+ return;
}
+
+ /* if the modem have not yet been enabled we need to make sure echoing is turned off */
+ command = g_strdup_printf ("E0");
+ mm_at_serial_port_queue_command (port, command, 3, NULL, NULL);
+ g_free (command);
+
+ mm_callback_info_set_data (info, "pin_type", g_strdup (pin_type), g_free);
+
+ command = g_strdup_printf ("^CPIN?");
+ mm_at_serial_port_queue_command (port, command, 3, send_huawei_cpin_done, info);
+ g_free (command);
}
+/*****************************************************************************/
/* Unsolicited message handlers */
static void
-handle_signal_quality_change (MMSerialPort *port,
+handle_signal_quality_change (MMAtSerialPort *port,
GMatchInfo *match_info,
gpointer user_data)
{
MMModemHuaweiGsm *self = MM_MODEM_HUAWEI_GSM (user_data);
- MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (self);
char *str;
- int quality;
+ int quality = 0;
str = g_match_info_fetch (match_info, 1);
quality = atoi (str);
g_free (str);
- if (quality == 99)
+ if (quality == 99) {
/* 99 means unknown */
quality = 0;
- else
+ } else {
/* Normalize the quality */
- quality = quality * 100 / 31;
+ quality = CLAMP (quality, 0, 31) * 100 / 31;
+ }
- g_debug ("Signal quality: %d", quality);
- priv->signal_quality = (guint32) quality;
- mm_modem_gsm_network_signal_quality (MM_MODEM_GSM_NETWORK (self), (guint32) quality);
+ mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (self), (guint32) quality);
}
static void
-handle_mode_change (MMSerialPort *port,
+handle_mode_change (MMAtSerialPort *port,
GMatchInfo *match_info,
gpointer user_data)
{
MMModemHuaweiGsm *self = MM_MODEM_HUAWEI_GSM (user_data);
- MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (self);
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
char *str;
int a;
int b;
@@ -472,29 +632,35 @@ handle_mode_change (MMSerialPort *port,
b = atoi (str);
g_free (str);
- if (a == 3 && b == 2)
- priv->mode = MM_MODEM_GSM_MODE_GPRS;
- else if (a == 3 && b == 3)
- priv->mode = MM_MODEM_GSM_MODE_EDGE;
- else if (a == 5 && b == 4)
- priv->mode = MM_MODEM_GSM_MODE_UMTS;
- else if (a == 5 && b == 5)
- priv->mode = MM_MODEM_GSM_MODE_HSDPA;
- else if (a == 5 && b == 6)
- priv->mode = MM_MODEM_GSM_MODE_HSUPA;
- else if (a == 5 && b == 7)
- priv->mode = MM_MODEM_GSM_MODE_HSPA;
+ 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;
+ } 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;
+ } else if (a == 0)
+ act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
else {
g_warning ("Couldn't parse mode change value: '%s'", str);
return;
}
- g_debug ("Mode: %d", priv->mode);
- mm_modem_gsm_network_mode (MM_MODEM_GSM_NETWORK (self), priv->mode);
+ g_debug ("Access Technology: %d", act);
+ mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (self), act);
}
static void
-handle_status_change (MMSerialPort *port,
+handle_status_change (MMAtSerialPort *port,
GMatchInfo *match_info,
gpointer user_data)
{
@@ -546,38 +712,35 @@ grab_port (MMModem *modem,
}
if (usbif == 0) {
- if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY))
+ if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY))
ptype = MM_PORT_TYPE_PRIMARY;
} else if (suggested_type == MM_PORT_TYPE_SECONDARY) {
- if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_SECONDARY))
+ if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_SECONDARY))
ptype = MM_PORT_TYPE_SECONDARY;
}
port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
- if (port && MM_IS_SERIAL_PORT (port)) {
- g_object_set (G_OBJECT (port), MM_PORT_CARRIER_DETECT, FALSE, NULL);
- if (ptype == MM_PORT_TYPE_SECONDARY) {
- GRegex *regex;
+ if (port && MM_IS_AT_SERIAL_PORT (port)) {
+ GRegex *regex;
- mm_generic_gsm_set_unsolicited_registration (MM_GENERIC_GSM (modem), TRUE);
+ g_object_set (G_OBJECT (port), MM_PORT_CARRIER_DETECT, FALSE, NULL);
- regex = g_regex_new ("\\r\\n\\^RSSI:(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, handle_signal_quality_change, modem, NULL);
- g_regex_unref (regex);
+ regex = g_regex_new ("\\r\\n\\^RSSI:(\\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, handle_signal_quality_change, modem, NULL);
+ g_regex_unref (regex);
- regex = g_regex_new ("\\r\\n\\^MODE:(\\d),(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, handle_mode_change, modem, NULL);
- g_regex_unref (regex);
+ regex = g_regex_new ("\\r\\n\\^MODE:(\\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, handle_mode_change, modem, NULL);
+ g_regex_unref (regex);
- regex = g_regex_new ("\\r\\n\\^DSFLOWRPT:(.+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, handle_status_change, modem, NULL);
- g_regex_unref (regex);
+ regex = g_regex_new ("\\r\\n\\^DSFLOWRPT:(.+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, handle_status_change, modem, NULL);
+ g_regex_unref (regex);
- regex = g_regex_new ("\\r\\n\\^BOOT:.+\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, modem, NULL);
- g_regex_unref (regex);
- }
+ regex = g_regex_new ("\\r\\n\\^BOOT:.+\\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, modem, NULL);
+ g_regex_unref (regex);
}
out:
@@ -598,11 +761,14 @@ modem_init (MMModem *modem_class)
static void
modem_gsm_network_init (MMModemGsmNetwork *class)
{
- class->set_network_mode = set_network_mode;
- class->get_network_mode = get_network_mode;
class->set_band = set_band;
class->get_band = get_band;
- class->get_signal_quality = get_signal_quality;
+}
+
+static void
+modem_gsm_card_init (MMModemGsmCard *class)
+{
+ class->get_unlock_retries = get_unlock_retries;
}
static void
@@ -614,8 +780,13 @@ static void
mm_modem_huawei_gsm_class_init (MMModemHuaweiGsmClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
mm_modem_huawei_gsm_parent_class = g_type_class_peek_parent (klass);
g_type_class_add_private (object_class, sizeof (MMModemHuaweiGsmPrivate));
+
+ 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-longcheer-gsm.c b/plugins/mm-modem-longcheer-gsm.c
new file mode 100644
index 0000000..62980f7
--- /dev/null
+++ b/plugins/mm-modem-longcheer-gsm.c
@@ -0,0 +1,222 @@
+/* -*- 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 "mm-modem-longcheer-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 (MMModemLongcheerGsm, mm_modem_longcheer_gsm, MM_TYPE_GENERIC_GSM)
+
+MMModem *
+mm_modem_longcheer_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin)
+{
+ 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_LONGCHEER_GSM,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ NULL));
+}
+
+/*****************************************************************************/
+
+static void
+get_allowed_mode_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ const char *p;
+ MMModemGsmAllowedMode mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+ gint mododr = -1;
+
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (info->error)
+ goto done;
+
+ p = mm_strip_tag (response->str, "+MODODR:");
+ if (!p) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Failed to parse the allowed mode response");
+ goto done;
+ }
+
+ mododr = atoi (p);
+ switch (mododr) {
+ case 1:
+ mode = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY;
+ break;
+ case 2:
+ case 4:
+ mode = MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED;
+ break;
+ case 3:
+ mode = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY;
+ break;
+ default:
+ break;
+ }
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mode), NULL);
+
+done:
+ 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, "AT+MODODR?", 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);
+}
+
+static void
+set_allowed_mode (MMGenericGsm *gsm,
+ MMModemGsmAllowedMode mode,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
+ char *command;
+ int mododr = 0;
+
+ 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:
+ mododr = 3;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY:
+ mododr = 1;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_ANY:
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED:
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED:
+ default:
+ mododr = 2;
+ break;
+ }
+
+ command = g_strdup_printf ("+MODODR=%d", mododr);
+ mm_at_serial_port_queue_command (port, command, 3, set_allowed_mode_done, info);
+ g_free (command);
+}
+
+static void
+get_act_request_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ const char *p;
+
+ if (error)
+ info->error = g_error_copy (error);
+ else {
+ p = mm_strip_tag (response->str, "+PSRAT:");
+ act = mm_gsm_string_to_access_tech (p);
+ }
+
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (act), NULL);
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_access_technology (MMGenericGsm *modem,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMAtSerialPort *port;
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (modem, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (port, "+PSRAT", 3, get_act_request_done, info);
+}
+
+/*****************************************************************************/
+
+static void
+mm_modem_longcheer_gsm_init (MMModemLongcheerGsm *self)
+{
+}
+
+static void
+mm_modem_longcheer_gsm_class_init (MMModemLongcheerGsmClass *klass)
+{
+ MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
+
+ mm_modem_longcheer_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;
+ gsm_class->get_access_technology = get_access_technology;
+}
+
diff --git a/plugins/mm-modem-longcheer-gsm.h b/plugins/mm-modem-longcheer-gsm.h
new file mode 100644
index 0000000..5383c52
--- /dev/null
+++ b/plugins/mm-modem-longcheer-gsm.h
@@ -0,0 +1,43 @@
+/* -*- 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_LONGCHEER_GSM_H
+#define MM_MODEM_LONGCHEER_GSM_H
+
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_LONGCHEER_GSM (mm_modem_longcheer_gsm_get_type ())
+#define MM_MODEM_LONGCHEER_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_LONGCHEER_GSM, MMModemLongcheerGsm))
+#define MM_MODEM_LONGCHEER_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_LONGCHEER_GSM, MMModemLongcheerGsmClass))
+#define MM_IS_MODEM_LONGCHEER_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_LONGCHEER_GSM))
+#define MM_IS_MODEM_LONGCHEER_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_LONGCHEER_GSM))
+#define MM_MODEM_LONGCHEER_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_LONGCHEER_GSM, MMModemLongcheerGsmClass))
+
+typedef struct {
+ MMGenericGsm parent;
+} MMModemLongcheerGsm;
+
+typedef struct {
+ MMGenericGsmClass parent;
+} MMModemLongcheerGsmClass;
+
+GType mm_modem_longcheer_gsm_get_type (void);
+
+MMModem *mm_modem_longcheer_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin);
+
+#endif /* MM_MODEM_LONGCHEER_H */
diff --git a/plugins/mm-modem-mbm.c b/plugins/mm-modem-mbm.c
index 686b35c..7f6bc9c 100644
--- a/plugins/mm-modem-mbm.c
+++ b/plugins/mm-modem-mbm.c
@@ -1,11 +1,13 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
- * Copyright (C) 2008 Ericsson AB
+ * Copyright (C) 2008 - 2010 Ericsson AB
+ * Copyright (C) 2009 - 2010 Red Hat, Inc.
*
* Author: Per Hallsmark <per.hallsmark@ericsson.com>
* Bjorn Runaker <bjorn.runaker@ericsson.com>
* Torgny Johansson <torgny.johansson@ericsson.com>
* Jonas Sjöquist <jonas.sjoquist@ericsson.com>
+ * Dan Williams <dcbw@redhat.com>
*
* 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
@@ -17,10 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
*/
#include <stdlib.h>
@@ -30,17 +28,20 @@
#include "mm-modem-mbm.h"
#include "mm-modem-simple.h"
+#include "mm-modem-gsm-card.h"
#include "mm-errors.h"
#include "mm-callback-info.h"
static void modem_init (MMModem *modem_class);
static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class);
static void modem_simple_init (MMModemSimple *class);
+static void modem_gsm_card_init (MMModemGsmCard *class);
G_DEFINE_TYPE_EXTENDED (MMModemMbm, mm_modem_mbm, MM_TYPE_GENERIC_GSM, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_NETWORK, modem_gsm_network_init)
- G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simple_init))
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simple_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_CARD, modem_gsm_card_init))
#define MM_MODEM_MBM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_MBM, MMModemMbmPrivate))
@@ -54,11 +55,6 @@ G_DEFINE_TYPE_EXTENDED (MMModemMbm, mm_modem_mbm, MM_TYPE_GENERIC_GSM, 0,
#define MBM_NETWORK_MODE_2G 5
#define MBM_NETWORK_MODE_3G 6
-#define MBM_ERINFO_2G_GPRS 1
-#define MBM_ERINFO_2G_EGPRS 2
-#define MBM_ERINFO_3G_UMTS 1
-#define MBM_ERINFO_3G_HSDPA 2
-
typedef struct {
guint reg_id;
gboolean have_emrdy;
@@ -83,12 +79,6 @@ mbm_modem_authenticate (MMModemMbm *self,
const char *password,
gpointer user_data);
-static const char *
-mbm_simple_get_string_property (GHashTable *properties, const char *name, GError **error);
-
-static uint
-mbm_simple_get_uint_property (GHashTable *properties, const char *name, GError **error);
-
MMModem *
mm_modem_mbm_new (const char *device,
const char *driver,
@@ -124,16 +114,9 @@ register_done (gpointer user_data)
MMModemMbm *self = MM_MODEM_MBM (reg_data->modem);
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
MMModemGsmNetwork *parent_modem_iface;
- MMSerialPort *primary;
priv->reg_id = 0;
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
-
- mm_serial_port_queue_command (primary, "+CREG=1", 3, NULL, NULL);
- mm_serial_port_queue_command (primary, "+CMER=3,0,0,1", 3, NULL, NULL);
-
parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GSM_NETWORK_GET_INTERFACE (self));
parent_modem_iface->do_register (MM_MODEM_GSM_NETWORK (self),
reg_data->network_id,
@@ -167,21 +150,16 @@ do_register (MMModemGsmNetwork *modem,
}
static int
-mbm_parse_network_mode (MMModemGsmMode network_mode)
+mbm_parse_allowed_mode (MMModemGsmAllowedMode network_mode)
{
switch (network_mode) {
- case MM_MODEM_GSM_MODE_ANY:
- case MM_MODEM_GSM_MODE_3G_PREFERRED:
- case MM_MODEM_GSM_MODE_2G_PREFERRED:
+ case MM_MODEM_GSM_ALLOWED_MODE_ANY:
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED:
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED:
return MBM_NETWORK_MODE_ANY;
- case MM_MODEM_GSM_MODE_GPRS:
- case MM_MODEM_GSM_MODE_EDGE:
- case MM_MODEM_GSM_MODE_2G_ONLY:
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY:
return MBM_NETWORK_MODE_2G;
- case MM_MODEM_GSM_MODE_3G_ONLY:
- case MM_MODEM_GSM_MODE_HSDPA:
- case MM_MODEM_GSM_MODE_HSUPA:
- case MM_MODEM_GSM_MODE_HSPA:
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY:
return MBM_NETWORK_MODE_3G;
default:
return MBM_NETWORK_MODE_ANY;
@@ -189,7 +167,7 @@ mbm_parse_network_mode (MMModemGsmMode network_mode)
}
static void
-mbm_set_network_mode_done (MMSerialPort *port,
+mbm_set_allowed_mode_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -203,92 +181,144 @@ mbm_set_network_mode_done (MMSerialPort *port,
}
static void
-set_network_mode (MMModemGsmNetwork *modem,
- MMModemGsmMode mode,
+set_allowed_mode (MMGenericGsm *gsm,
+ MMModemGsmAllowedMode mode,
MMModemFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
char *command;
- MMSerialPort *primary;
+ MMAtSerialPort *port;
- info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
+ 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", mbm_parse_network_mode (mode));
- mm_serial_port_queue_command (primary, command, 3, mbm_set_network_mode_done, info);
+ command = g_strdup_printf ("+CFUN=%d", mbm_parse_allowed_mode (mode));
+ mm_at_serial_port_queue_command (port, command, 3, mbm_set_allowed_mode_done, info);
g_free (command);
}
static void
-get_network_mode_done (MMSerialPort *port,
+mbm_erinfo_received (MMAtSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data)
+{
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ char *str;
+
+ str = g_match_info_fetch (info, 2);
+ if (str) {
+ switch (atoi (str)) {
+ case 1:
+ act = MM_MODEM_GSM_ACCESS_TECH_GPRS;
+ break;
+ case 2:
+ act = MM_MODEM_GSM_ACCESS_TECH_EDGE;
+ break;
+ default:
+ break;
+ }
+ }
+ g_free (str);
+
+ /* 3G modes take precedence */
+ str = g_match_info_fetch (info, 3);
+ if (str) {
+ switch (atoi (str)) {
+ case 1:
+ act = MM_MODEM_GSM_ACCESS_TECH_UMTS;
+ break;
+ case 2:
+ act = MM_MODEM_GSM_ACCESS_TECH_HSDPA;
+ break;
+ default:
+ break;
+ }
+ }
+ g_free (str);
+
+ mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (user_data), act);
+}
+
+static void
+get_allowed_mode_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- char *erinfo;
- int mode = 0, gsm = 0, umts = 0;
gboolean parsed = FALSE;
- if (error) {
+ if (error)
info->error = g_error_copy (error);
- goto done;
- }
-
- erinfo = strstr (response->str, "*ERINFO:");
- if (!erinfo)
- goto done;
-
- if (sscanf (erinfo + 8, "%d,%d,%d", &mode, &gsm, &umts) != 3)
- goto done;
+ else if (!g_str_has_prefix (response->str, "CFUN: ")) {
+ MMModemGsmAllowedMode mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+ int a;
- if (gsm || umts) {
- MMModemGsmMode mm_mode = MM_MODEM_GSM_MODE_ANY;
-
- if (gsm == MBM_ERINFO_2G_GPRS)
- mm_mode = MM_MODEM_GSM_MODE_GPRS;
- else if (gsm == MBM_ERINFO_2G_EGPRS)
- mm_mode = MM_MODEM_GSM_MODE_EDGE;
- else if (umts == MBM_ERINFO_3G_UMTS)
- mm_mode = MM_MODEM_GSM_MODE_UMTS;
- else if (umts == MBM_ERINFO_3G_HSDPA)
- mm_mode = MM_MODEM_GSM_MODE_HSDPA;
- else
- g_debug ("%s unknown network mode %d,%d", __FUNCTION__, gsm, umts);
+ a = atoi (response->str + 6);
+ if (a == MBM_NETWORK_MODE_2G)
+ mode = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY;
+ else if (a == MBM_NETWORK_MODE_3G)
+ mode = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY;
- mm_callback_info_set_result (info, GUINT_TO_POINTER (mm_mode), NULL);
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mode), NULL);
parsed = TRUE;
}
-done:
- if (!error && !parsed) {
+ if (!error && !parsed)
info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Could not parse network mode results");
- }
+ "Could not parse allowed mode results");
mm_callback_info_schedule (info);
}
static void
-get_network_mode (MMModemGsmNetwork *modem,
+get_allowed_mode (MMGenericGsm *gsm,
MMModemUIntFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
- MMSerialPort *primary;
+ MMAtSerialPort *port;
- info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
- mm_serial_port_queue_command (primary, "*ERINFO?", 3, get_network_mode_done, info);
+ 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);
}
/*****************************************************************************/
/* Simple Modem class override functions */
/*****************************************************************************/
+static const char *
+mbm_simple_get_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_get_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,
@@ -298,14 +328,10 @@ simple_connect (MMModemSimple *simple,
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (simple);
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMModemSimple *parent_iface;
- uint network_mode = 0;
priv->username = mbm_simple_get_string_property (properties, "username", &info->error);
priv->password = mbm_simple_get_string_property (properties, "password", &info->error);
- network_mode = mbm_simple_get_uint_property (properties, "network_mode", &info->error);
- priv->network_mode = mbm_parse_network_mode (network_mode);
-
parent_iface = g_type_interface_peek_parent (MM_MODEM_SIMPLE_GET_INTERFACE (simple));
parent_iface->connect (MM_MODEM_SIMPLE (simple), properties, callback, info);
}
@@ -315,18 +341,22 @@ simple_connect (MMModemSimple *simple,
/*****************************************************************************/
static void
-mbm_enable_done (MMSerialPort *port,
+mbm_enable_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
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);
}
static void
-mbm_enap0_done (MMSerialPort *port,
+mbm_enap0_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -339,12 +369,12 @@ mbm_enap0_done (MMSerialPort *port,
priv->network_mode = MBM_NETWORK_MODE_ANY;
command = g_strdup_printf ("+CFUN=%d", priv->network_mode);
- mm_serial_port_queue_command (port, command, 3, mbm_enable_done, info);
+ mm_at_serial_port_queue_command (port, command, 3, mbm_enable_done, info);
g_free (command);
}
static void
-mbm_init_done (MMSerialPort *port,
+mbm_init_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -360,17 +390,17 @@ mbm_init_done (MMSerialPort *port,
if (!priv->network_mode)
priv->network_mode = MBM_NETWORK_MODE_ANY;
- mm_serial_port_queue_command (port, "*ENAP=0", 3, mbm_enap0_done, info);
+ mm_at_serial_port_queue_command (port, "*ENAP=0", 3, mbm_enap0_done, info);
}
static void
-do_init (MMSerialPort *port, MMCallbackInfo *info)
+do_init (MMAtSerialPort *port, MMCallbackInfo *info)
{
- mm_serial_port_queue_command (port, "&F E0 V1 X4 &C1 +CMEE=1", 3, mbm_init_done, info);
+ mm_at_serial_port_queue_command (port, "&F E0 V1 X4 &C1 +CMEE=1", 3, mbm_init_done, info);
}
static void
-mbm_emrdy_done (MMSerialPort *port,
+mbm_emrdy_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -378,11 +408,9 @@ mbm_emrdy_done (MMSerialPort *port,
MMCallbackInfo *info = user_data;
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (info->modem);
- if ( error
- && error->domain == MM_SERIAL_ERROR
- && error->code == MM_SERIAL_RESPONSE_TIMEOUT) {
+ if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT))
g_warning ("%s: timed out waiting for EMRDY response.", __func__);
- } else
+ else
priv->have_emrdy = TRUE;
do_init (port, info);
@@ -393,18 +421,18 @@ do_enable (MMGenericGsm *self, MMModemFn callback, gpointer user_data)
{
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
MMCallbackInfo *info;
- MMSerialPort *primary;
+ MMAtSerialPort *primary;
info = mm_callback_info_new (MM_MODEM (self), callback, user_data);
- primary = mm_generic_gsm_get_port (self, MM_PORT_TYPE_PRIMARY);
+ primary = mm_generic_gsm_get_at_port (self, MM_PORT_TYPE_PRIMARY);
g_assert (primary);
if (priv->have_emrdy) {
/* Modem is ready, no need to check EMRDY */
do_init (primary, info);
} else
- mm_serial_port_queue_command (primary, "*EMRDY?", 5, mbm_emrdy_done, info);
+ mm_at_serial_port_queue_command (primary, "*EMRDY?", 5, mbm_emrdy_done, info);
}
typedef struct {
@@ -414,10 +442,10 @@ typedef struct {
} DisableInfo;
static void
-disable_creg_cmer_done (MMSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
+disable_unsolicited_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
MMModem *parent_modem_iface;
@@ -433,7 +461,7 @@ disable (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
- MMSerialPort *primary;
+ MMAtSerialPort *primary;
DisableInfo *info;
info = g_malloc0 (sizeof (DisableInfo));
@@ -441,11 +469,11 @@ disable (MMModem *modem,
info->user_data = user_data;
info->modem = modem;
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
g_assert (primary);
- /* Turn off unsolicited +CIEV signal strength indicator */
- mm_serial_port_queue_command (primary, "+CREG=0;+CMER=0", 5, disable_creg_cmer_done, info);
+ /* Turn off unsolicited responses */
+ mm_at_serial_port_queue_command (primary, "+CMER=0;*ERINFO=0", 5, disable_unsolicited_done, info);
}
static void
@@ -466,29 +494,77 @@ do_connect (MMModem *modem,
}
static void
-disconnect (MMModem *modem,
- MMModemFn callback,
- gpointer user_data)
+do_disconnect (MMGenericGsm *gsm,
+ gint cid,
+ MMModemFn callback,
+ gpointer user_data)
{
- MMCallbackInfo *info;
- MMSerialPort *primary;
-
- mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE);
+ MMAtSerialPort *primary;
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ primary = mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY);
g_assert (primary);
- mm_serial_port_queue_command (primary, "*ENAP=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (primary, "*ENAP=0", 3, NULL, NULL);
- mm_generic_gsm_update_enabled_state (MM_GENERIC_GSM (modem), FALSE, MM_MODEM_STATE_REASON_NONE);
+ MM_GENERIC_GSM_CLASS (mm_modem_mbm_parent_class)->do_disconnect (gsm, cid, callback, user_data);
+}
- info = mm_callback_info_new (modem, callback, user_data);
+static void
+factory_reset_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ mm_serial_port_close (MM_SERIAL_PORT (port));
mm_callback_info_schedule (info);
}
+static void
+factory_reset (MMModem *self,
+ const char *code,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMAtSerialPort *port;
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new (self, 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 (self), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ /* Modem may not be enabled yet, which sometimes can't be done until
+ * the device has been unlocked. In this case we have to open the port
+ * ourselves.
+ */
+ if (!mm_serial_port_open (MM_SERIAL_PORT (port), &info->error)) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (port, "&F +CMEE=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+COPS=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CR=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CRC=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CREG=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CMER=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "*EPEE=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CNMI=2, 0, 0, 0, 0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CGREG=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "*EIAD=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CGSMS=3", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CSCA=\"\",129", 3, factory_reset_done, info);
+}
+
/*****************************************************************************/
static void
-mbm_emrdy_received (MMSerialPort *port,
+mbm_emrdy_received (MMAtSerialPort *port,
GMatchInfo *info,
gpointer user_data)
{
@@ -496,7 +572,7 @@ mbm_emrdy_received (MMSerialPort *port,
}
static void
-mbm_pacsp_received (MMSerialPort *port,
+mbm_pacsp_received (MMAtSerialPort *port,
GMatchInfo *info,
gpointer user_data)
{
@@ -504,65 +580,78 @@ mbm_pacsp_received (MMSerialPort *port,
}
static void
-mbm_ciev_received (MMSerialPort *port,
+mbm_ciev_received (MMAtSerialPort *port,
GMatchInfo *info,
gpointer user_data)
{
int quality = 0, ind = 0;
- const char *str;
+ 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_modem_gsm_network_signal_quality (MM_MODEM_GSM_NETWORK (user_data), quality * 20);
+ mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (user_data), quality * 20);
}
+ g_free (str);
}
}
static void
-mbm_do_connect_done (MMModemMbm *self)
+mbm_do_connect_done (MMModemMbm *self, gboolean success)
{
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
- if (priv->pending_connect_info) {
+ if (!priv->pending_connect_info)
+ return;
+
+ if (success)
mm_generic_gsm_connect_complete (MM_GENERIC_GSM (self), NULL, priv->pending_connect_info);
- priv->pending_connect_info = NULL;
+ else {
+ GError *connect_error;
+
+ connect_error = mm_modem_connect_error_for_code (MM_MODEM_CONNECT_ERROR_BUSY);
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (self), connect_error, priv->pending_connect_info);
+ g_error_free (connect_error);
}
+ priv->pending_connect_info = NULL;
}
static void
-mbm_e2nap_received (MMSerialPort *port,
+mbm_e2nap_received (MMAtSerialPort *port,
GMatchInfo *info,
gpointer user_data)
{
int state = 0;
- const char *str;
+ char *str;
str = g_match_info_fetch (info, 1);
if (str)
state = atoi (str);
-
- if (MBM_E2NAP_DISCONNECTED == state)
- g_debug ("%s, disconnected", __func__);
- else if (MBM_E2NAP_CONNECTED == state) {
- g_debug ("%s, connected", __func__);
- mbm_do_connect_done (MM_MODEM_MBM (user_data));
+ g_free (str);
+
+ if (MBM_E2NAP_DISCONNECTED == state) {
+ g_debug ("%s: disconnected", __func__);
+ mbm_do_connect_done (MM_MODEM_MBM (user_data), FALSE);
+ } else if (MBM_E2NAP_CONNECTED == state) {
+ g_debug ("%s: connected", __func__);
+ mbm_do_connect_done (MM_MODEM_MBM (user_data), TRUE);
} else if (MBM_E2NAP_CONNECTING == state)
- g_debug("%s, connecting", __func__);
+ g_debug("%s: connecting", __func__);
else {
/* Should not happen */
- g_debug("%s, undefined e2nap status",__FUNCTION__);
- g_assert_not_reached ();
+ g_debug("%s: unhandled E2NAP state %d", __func__, state);
+ mbm_do_connect_done (MM_MODEM_MBM (user_data), FALSE);
}
}
static void
-enap_poll_response (MMSerialPort *port,
+enap_poll_response (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -597,20 +686,21 @@ static gboolean
enap_poll (gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMSerialPort *port = mm_generic_gsm_get_port (MM_GENERIC_GSM (info->modem), MM_PORT_TYPE_PRIMARY);
+ MMAtSerialPort *port;
+ port = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (info->modem), MM_PORT_TYPE_PRIMARY);
g_assert (port);
- mm_serial_port_queue_command (port, "AT*ENAP?", 3, enap_poll_response, user_data);
+ mm_at_serial_port_queue_command (port, "AT*ENAP?", 3, enap_poll_response, user_data);
/* we cancel this in the _done function if all is fine */
return TRUE;
}
static void
-enap_done (MMSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
+enap_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
guint tid;
@@ -623,12 +713,11 @@ enap_done (MMSerialPort *port,
tid = g_timeout_add_seconds (1, enap_poll, user_data);
/* remember poll id as callback info object, with source_remove as free func */
mm_callback_info_set_data (info, "mbm-enap-poll-id", GUINT_TO_POINTER (tid), (GFreeFunc) g_source_remove);
- mm_serial_port_queue_command (port, "AT*E2NAP=1", 3, NULL, NULL);
}
static void
mbm_auth_done (MMSerialPort *port,
- GString *response,
+ GByteArray *response,
GError *error,
gpointer user_data)
{
@@ -643,8 +732,11 @@ mbm_auth_done (MMSerialPort *port,
}
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);
- mm_serial_port_queue_command (port, command, 3, enap_done, user_data);
+ mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), command, 3, enap_done, user_data);
g_free (command);
}
@@ -654,61 +746,133 @@ mbm_modem_authenticate (MMModemMbm *self,
const char *password,
gpointer user_data)
{
- MMSerialPort *primary;
+ MMAtSerialPort *primary;
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
+ primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
g_assert (primary);
if (username || password) {
- char *command;
+ GByteArray *command;
+ MMModemCharset cur_set;
+ char *tmp;
+
+ /* F3507g at least wants the username and password to be sent in the
+ * modem's current character set.
+ */
+ cur_set = mm_generic_gsm_get_charset (MM_GENERIC_GSM (self));
+
+ command = g_byte_array_sized_new (75);
+ tmp = g_strdup_printf ("AT*EIAAUW=%d,1,", mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)));
+ g_byte_array_append (command, (const guint8 *) tmp, strlen (tmp));
+ g_free (tmp);
+
+ if (username)
+ mm_modem_charset_byte_array_append (command, username, TRUE, cur_set);
+ else
+ g_byte_array_append (command, (const guint8 *) "\"\"", 2);
- command = g_strdup_printf ("*EIAAUW=%d,1,\"%s\",\"%s\"",
- mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)),
- username ? username : "",
- password ? password : "");
+ g_byte_array_append (command, (const guint8 *) ",", 1);
- mm_serial_port_queue_command (primary, command, 3, mbm_auth_done, user_data);
- g_free (command);
+ if (password)
+ mm_modem_charset_byte_array_append (command, password, TRUE, cur_set);
+ else
+ g_byte_array_append (command, (const guint8 *) "\"\"", 2);
+
+ g_byte_array_append (command, (const guint8 *) "\r", 1);
+
+ mm_serial_port_queue_command (MM_SERIAL_PORT (primary),
+ command,
+ TRUE,
+ 3,
+ mbm_auth_done,
+ user_data);
} else
- mbm_auth_done (primary, NULL, NULL, user_data);
+ mbm_auth_done (MM_SERIAL_PORT (primary), NULL, NULL, user_data);
}
-static const char *
-mbm_simple_get_string_property (GHashTable *properties, const char *name, GError **error)
+/*****************************************************************************/
+
+static void
+send_epin_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
- GValue *value;
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ const char *pin_type;
+ int attempts_left = 0;
- value = (GValue *) g_hash_table_lookup (properties, name);
- if (!value)
- return NULL;
+ if (error) {
+ info->error = g_error_copy (error);
+ goto done;
+ }
- if (G_VALUE_HOLDS_STRING (value))
- return g_value_get_string (value);
+ pin_type = mm_callback_info_get_data (info, "pin_type");
- 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));
+ if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PIN))
+ sscanf (response->str, "*EPIN: %d", &attempts_left);
+ else if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PUK))
+ sscanf (response->str, "*EPIN: %*d, %d", &attempts_left);
+ else if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PIN2))
+ sscanf (response->str, "*EPIN: %*d, %*d, %d", &attempts_left);
+ 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);
- return NULL;
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Unhandled PIN type");
+ }
+
+ if (attempts_left < 0 || attempts_left > 998) {
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Invalid PIN attempts left %d", attempts_left);
+ attempts_left = 0;
+ }
+
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (attempts_left), NULL);
+
+done:
+ mm_serial_port_close (MM_SERIAL_PORT (port));
+ mm_callback_info_schedule (info);
}
-static uint
-mbm_simple_get_uint_property (GHashTable *properties, const char *name, GError **error)
+static void
+mbm_get_unlock_retries (MMModemGsmCard *modem,
+ const char *pin_type,
+ MMModemUIntFn callback,
+ gpointer user_data)
{
- GValue *value;
+ MMAtSerialPort *port;
+ char *command;
+ MMCallbackInfo *info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- value = (GValue *) g_hash_table_lookup (properties, name);
- if (!value)
- return 0;
+ g_debug ("%s: pin type '%s'", __func__, pin_type);
- if (G_VALUE_HOLDS_UINT (value))
- return g_value_get_uint (value);
+ /* 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_callback_info_schedule (info);
+ return;
+ }
- g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Invalid property type for '%s': %s (uint expected)",
- name, G_VALUE_TYPE_NAME (value));
+ /* Modem may not be enabled yet, which sometimes can't be done until
+ * the device has been unlocked. In this case we have to open the port
+ * ourselves.
+ */
+ if (!mm_serial_port_open (MM_SERIAL_PORT (port), &info->error)) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ /* if the modem have not yet been enabled we need to make sure echoing is turned off */
+ command = g_strdup_printf ("E0");
+ mm_at_serial_port_queue_command (port, command, 3, NULL, NULL);
+ g_free (command);
- return 0;
+ mm_callback_info_set_data (info, "pin_type", g_strdup (pin_type), g_free);
+
+ command = g_strdup_printf ("*EPIN?");
+ mm_at_serial_port_queue_command (port, command, 3, send_epin_done, info);
+ g_free (command);
}
/*****************************************************************************/
@@ -727,43 +891,52 @@ grab_port (MMModem *modem,
if (!strcmp (subsys, "tty")) {
if (suggested_type == MM_PORT_TYPE_UNKNOWN) {
- if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY))
+ if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY))
ptype = MM_PORT_TYPE_PRIMARY;
- else if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_SECONDARY))
+ 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_SERIAL_PORT (port) && (ptype == MM_PORT_TYPE_PRIMARY)) {
+ if (port && MM_IS_AT_SERIAL_PORT (port)) {
GRegex *regex;
- mm_generic_gsm_set_unsolicited_registration (MM_GENERIC_GSM (modem), TRUE);
+ if (ptype == MM_PORT_TYPE_PRIMARY) {
+ regex = g_regex_new ("\\r\\n\\*E2NAP: (\\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_e2nap_received, modem, NULL);
+ g_regex_unref (regex);
- regex = g_regex_new ("\\r\\n\\*EMRDY: \\d\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_emrdy_received, modem, NULL);
- g_regex_unref (regex);
+ /* Catch the extended error status bit of the command too */
+ regex = g_regex_new ("\\r\\n\\*E2NAP: (\\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_e2nap_received, modem, NULL);
+ g_regex_unref (regex);
+ }
- regex = g_regex_new ("\\r\\n\\*E2NAP: (\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_e2nap_received, modem, NULL);
+ regex = g_regex_new ("\\r\\n\\*EMRDY: \\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_emrdy_received, modem, NULL);
g_regex_unref (regex);
regex = g_regex_new ("\\r\\n\\+PACSP(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_pacsp_received, modem, NULL);
+ 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_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_ciev_received, modem, 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_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, modem, NULL);
+ 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);
g_regex_unref (regex);
regex = g_regex_new ("\\r\\n\\*EMWI: (\\d),(\\d).*\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, 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\\*ERINFO:\\s*(\\d),(\\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_erinfo_received, modem, NULL);
g_regex_unref (regex);
}
@@ -773,11 +946,15 @@ grab_port (MMModem *modem,
/*****************************************************************************/
static void
+modem_gsm_card_init (MMModemGsmCard *class)
+{
+ class->get_unlock_retries = mbm_get_unlock_retries;
+}
+
+static void
modem_gsm_network_init (MMModemGsmNetwork *class)
{
class->do_register = do_register;
- class->get_network_mode = get_network_mode;
- class->set_network_mode = set_network_mode;
}
static void
@@ -792,7 +969,7 @@ modem_init (MMModem *modem_class)
modem_class->grab_port = grab_port;
modem_class->disable = disable;
modem_class->connect = do_connect;
- modem_class->disconnect = disconnect;
+ modem_class->factory_reset = factory_reset;
}
static void
@@ -826,5 +1003,8 @@ mm_modem_mbm_class_init (MMModemMbmClass *klass)
object_class->finalize = finalize;
gsm_class->do_enable = do_enable;
+ gsm_class->do_disconnect = do_disconnect;
+ gsm_class->get_allowed_mode = get_allowed_mode;
+ gsm_class->set_allowed_mode = set_allowed_mode;
}
diff --git a/plugins/mm-modem-mbm.h b/plugins/mm-modem-mbm.h
index 8756e47..db0f627 100644
--- a/plugins/mm-modem-mbm.h
+++ b/plugins/mm-modem-mbm.h
@@ -17,10 +17,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
*/
#ifndef MM_MODEM_MBM_H
diff --git a/plugins/mm-modem-nokia.c b/plugins/mm-modem-nokia.c
index 677a089..eb90287 100644
--- a/plugins/mm-modem-nokia.c
+++ b/plugins/mm-modem-nokia.c
@@ -56,19 +56,19 @@ grab_port (MMModem *modem,
MMPort *port = NULL;
if (suggested_type == MM_PORT_TYPE_UNKNOWN) {
- if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY))
+ if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY))
ptype = MM_PORT_TYPE_PRIMARY;
- else if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_SECONDARY))
+ 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_SERIAL_PORT (port)) {
- mm_serial_port_set_response_parser (MM_SERIAL_PORT (port),
- mm_serial_parser_v1_e1_parse,
- mm_serial_parser_v1_e1_new (),
- mm_serial_parser_v1_e1_destroy);
+ if (port && MM_IS_AT_SERIAL_PORT (port)) {
+ mm_at_serial_port_set_response_parser (MM_AT_SERIAL_PORT (port),
+ mm_serial_parser_v1_e1_parse,
+ mm_serial_parser_v1_e1_new (),
+ mm_serial_parser_v1_e1_destroy);
}
return !!port;
diff --git a/plugins/mm-modem-novatel-cdma.c b/plugins/mm-modem-novatel-cdma.c
new file mode 100644
index 0000000..64ee15f
--- /dev/null
+++ b/plugins/mm-modem-novatel-cdma.c
@@ -0,0 +1,183 @@
+/* -*- 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "mm-modem-novatel-cdma.h"
+#include "mm-errors.h"
+#include "mm-callback-info.h"
+
+static void modem_cdma_init (MMModemCdma *cdma_class);
+
+G_DEFINE_TYPE_EXTENDED (MMModemNovatelCdma, mm_modem_novatel_cdma, MM_TYPE_GENERIC_CDMA, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_CDMA, modem_cdma_init))
+
+
+MMModem *
+mm_modem_novatel_cdma_new (const char *device,
+ const char *driver,
+ const char *plugin,
+ gboolean evdo_rev0,
+ gboolean evdo_revA)
+{
+ 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_NOVATEL_CDMA,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ MM_GENERIC_CDMA_EVDO_REV0, evdo_rev0,
+ MM_GENERIC_CDMA_EVDO_REVA, evdo_revA,
+ NULL));
+}
+
+/*****************************************************************************/
+
+static void
+parent_csq_done (MMModem *modem,
+ guint32 result,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+
+ if (error)
+ info->error = g_error_copy (error);
+ else
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (result), NULL);
+ mm_callback_info_schedule (info);
+}
+
+static int
+get_one_qual (const char *reply, const char *tag)
+{
+ int qual = -1;
+ const char *p;
+
+ p = strstr (reply, tag);
+ if (!p)
+ return -1;
+
+ /* Skip the tag */
+ p += strlen (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));
+ }
+ }
+
+ return qual;
+}
+
+static void
+get_rssi_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemCdma *parent_iface;
+ int qual;
+
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (info->error) {
+ if (info->modem) {
+ /* Fallback to parent's method */
+ g_clear_error (&info->error);
+ parent_iface = g_type_interface_peek_parent (MM_MODEM_CDMA_GET_INTERFACE (info->modem));
+ parent_iface->get_signal_quality (MM_MODEM_CDMA (info->modem), parent_csq_done, info);
+ } else
+ mm_callback_info_schedule (info);
+
+ return;
+ }
+
+ /* Parse the signal quality */
+ qual = get_one_qual (response->str, "RX0=");
+ if (qual < 0)
+ qual = get_one_qual (response->str, "RX1=");
+
+ if (qual >= 0) {
+ mm_callback_info_set_result (info, GUINT_TO_POINTER ((guint32) qual), NULL);
+ mm_generic_cdma_update_cdma1x_quality (MM_GENERIC_CDMA (info->modem), (guint32) qual);
+ } else {
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "%s", "Could not parse signal quality results");
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_signal_quality (MMModemCdma *modem,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
+ MMModemCdma *parent_iface;
+
+ port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (modem), NULL);
+ if (!port) {
+ /* Let the superclass handle it */
+ parent_iface = g_type_interface_peek_parent (MM_MODEM_CDMA_GET_INTERFACE (modem));
+ parent_iface->get_signal_quality (MM_MODEM_CDMA (modem), callback, user_data);
+ return;
+ }
+
+ info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
+
+ /* Many Novatel CDMA cards don't report CSQ in standard 0 - 31 and the CSQ
+ * reply doesn't appear to be in positive dBm either; instead try the custom
+ * Novatel command for it.
+ */
+ mm_at_serial_port_queue_command (port, "$NWRSSI", 3, get_rssi_done, info);
+}
+
+/*****************************************************************************/
+
+static void
+modem_cdma_init (MMModemCdma *cdma_class)
+{
+ cdma_class->get_signal_quality = get_signal_quality;
+}
+
+static void
+mm_modem_novatel_cdma_init (MMModemNovatelCdma *self)
+{
+}
+
+static void
+mm_modem_novatel_cdma_class_init (MMModemNovatelCdmaClass *klass)
+{
+ mm_modem_novatel_cdma_parent_class = g_type_class_peek_parent (klass);
+}
+
diff --git a/plugins/mm-modem-novatel-cdma.h b/plugins/mm-modem-novatel-cdma.h
new file mode 100644
index 0000000..4d38d8e
--- /dev/null
+++ b/plugins/mm-modem-novatel-cdma.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_NOVATEL_CDMA_H
+#define MM_MODEM_NOVATEL_CDMA_H
+
+#include "mm-generic-cdma.h"
+
+#define MM_TYPE_MODEM_NOVATEL_CDMA (mm_modem_novatel_cdma_get_type ())
+#define MM_MODEM_NOVATEL_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_NOVATEL_CDMA, MMModemNovatelCdma))
+#define MM_MODEM_NOVATEL_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_NOVATEL_CDMA, MMModemNovatelCdmaClass))
+#define MM_IS_MODEM_NOVATEL_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_NOVATEL_CDMA))
+#define MM_IS_MODEM_NOVATEL_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_NOVATEL_CDMA))
+#define MM_MODEM_NOVATEL_CDMA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_NOVATEL_CDMA, MMModemNovatelCdmaClass))
+
+typedef struct {
+ MMGenericCdma parent;
+} MMModemNovatelCdma;
+
+typedef struct {
+ MMGenericCdmaClass parent;
+} MMModemNovatelCdmaClass;
+
+GType mm_modem_novatel_cdma_get_type (void);
+
+MMModem *mm_modem_novatel_cdma_new (const char *device,
+ const char *driver,
+ const char *plugin,
+ gboolean evdo_rev0,
+ gboolean evdo_revA);
+
+#endif /* MM_MODEM_NOVATEL_CDMA_H */
diff --git a/plugins/mm-modem-novatel-gsm.c b/plugins/mm-modem-novatel-gsm.c
index 8189627..584156f 100644
--- a/plugins/mm-modem-novatel-gsm.c
+++ b/plugins/mm-modem-novatel-gsm.c
@@ -11,9 +11,10 @@
* 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 <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -21,6 +22,7 @@
#include "mm-modem-novatel-gsm.h"
#include "mm-errors.h"
#include "mm-callback-info.h"
+#include "mm-modem-helpers.h"
static void modem_init (MMModem *modem_class);
@@ -49,114 +51,246 @@ mm_modem_novatel_gsm_new (const char *device,
/*****************************************************************************/
static void
-init_modem_done (MMSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
+dmat_callback2 (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
-
- mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
+ mm_serial_port_close (MM_SERIAL_PORT (port));
}
static void
-pin_check_done (MMModem *modem, GError *error, gpointer user_data)
+dmat_callback (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMGenericGsm *self = MM_GENERIC_GSM (modem);
- MMSerialPort *primary;
-
if (error) {
- mm_generic_gsm_enable_complete (self, error, info);
- return;
+ /* Try it again */
+ if (mm_serial_port_open (MM_SERIAL_PORT (port), NULL))
+ mm_at_serial_port_queue_command (port, "$NWDMAT=1", 2, dmat_callback2, NULL);
+ }
+
+ mm_serial_port_close (MM_SERIAL_PORT (port));
+}
+
+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) && (ptype == MM_PORT_TYPE_PRIMARY)) {
+ /* Flip secondary ports to AT mode */
+ if (mm_serial_port_open (MM_SERIAL_PORT (port), NULL))
+ mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "$NWDMAT=1", 2, dmat_callback, NULL);
}
- /* Finish the initialization */
- primary = mm_generic_gsm_get_port (self, MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
- mm_serial_port_queue_command (primary, "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1", 10, init_modem_done, info);
+ return !!port;
}
+/*****************************************************************************/
+
static void
-pre_init_done (MMSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
+set_allowed_mode_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- if (error) {
- mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
+ 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;
+ MMAtSerialPort *port;
+ char *command;
+ int nw_mode = 0; /* 3G preferred */
+
+ 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;
}
- /* Now check the PIN explicitly, novatel doesn't seem to report
- * that it needs it otherwise.
- */
- mm_generic_gsm_check_pin (MM_GENERIC_GSM (info->modem), pin_check_done, info);
+ switch (mode) {
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY:
+ nw_mode = 1;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY:
+ nw_mode = 2;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED:
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED:
+ case MM_MODEM_GSM_ALLOWED_MODE_ANY:
+ default:
+ break;
+ }
+
+ command = g_strdup_printf ("$NWRAT=%d,2", nw_mode);
+ mm_at_serial_port_queue_command (port, command, 3, set_allowed_mode_done, info);
+ g_free (command);
+}
+
+static gboolean
+parse_nwrat_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 ("\\$NWRAT:\\s*(\\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, 1);
+ 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_3G_PREFERRED;
+ 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
-enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
+get_allowed_mode_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
- MMCallbackInfo *info = user_data;
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemGsmAllowedMode mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
- if (error)
- mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
- else
- mm_serial_port_queue_command (port, "E0 V1", 3, pre_init_done, user_data);
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (!info->error) {
+ parse_nwrat_response (response, &mode, &info->error);
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mode), NULL);
+ }
+
+ mm_callback_info_schedule (info);
}
static void
-do_enable (MMGenericGsm *modem, MMModemFn callback, gpointer user_data)
+get_allowed_mode (MMGenericGsm *gsm,
+ MMModemUIntFn callback,
+ gpointer user_data)
{
MMCallbackInfo *info;
- MMSerialPort *primary;
+ MMAtSerialPort *port;
- primary = mm_generic_gsm_get_port (modem, MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
+ info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data);
- info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
- mm_serial_port_flash (primary, 100, enable_flash_done, info);
+ 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, "$NWRAT?", 3, get_allowed_mode_done, info);
}
static void
-dmat_callback (MMSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
+get_act_request_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
- mm_serial_port_close (port);
+ MMCallbackInfo *info = user_data;
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ const char *p;
+
+ if (error)
+ info->error = g_error_copy (error);
+ else {
+ p = mm_strip_tag (response->str, "$CNTI:");
+ p = strchr (p, ',');
+ if (p)
+ act = mm_gsm_string_to_access_tech (p + 1);
+ }
+
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (act), NULL);
+ mm_callback_info_schedule (info);
}
-static gboolean
-grab_port (MMModem *modem,
- const char *subsys,
- const char *name,
- MMPortType suggested_type,
- gpointer user_data,
- GError **error)
+static void
+get_access_technology (MMGenericGsm *modem,
+ MMModemUIntFn callback,
+ gpointer user_data)
{
- MMGenericGsm *gsm = MM_GENERIC_GSM (modem);
- MMPortType ptype = MM_PORT_TYPE_IGNORED;
- MMPort *port = NULL;
+ MMAtSerialPort *port;
+ MMCallbackInfo *info;
- if (suggested_type == MM_PORT_TYPE_UNKNOWN) {
- if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY))
- ptype = MM_PORT_TYPE_PRIMARY;
- else if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_SECONDARY))
- ptype = MM_PORT_TYPE_SECONDARY;
- } else
- ptype = suggested_type;
+ info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
- if (port && MM_IS_SERIAL_PORT (port) && (ptype == MM_PORT_TYPE_PRIMARY)) {
- /* Flip secondary ports to AT mode */
- if (mm_serial_port_open (MM_SERIAL_PORT (port), NULL))
- mm_serial_port_queue_command (MM_SERIAL_PORT (port), "$NWDMAT=1", 2, dmat_callback, NULL);
+ port = mm_generic_gsm_get_best_at_port (modem, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
}
- return !!port;
+ mm_at_serial_port_queue_command (port, "$CNTI=0", 3, get_act_request_done, info);
}
/*****************************************************************************/
@@ -179,6 +313,8 @@ mm_modem_novatel_gsm_class_init (MMModemNovatelGsmClass *klass)
mm_modem_novatel_gsm_parent_class = g_type_class_peek_parent (klass);
- gsm_class->do_enable = do_enable;
+ 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-option-utils.c b/plugins/mm-modem-option-utils.c
new file mode 100644
index 0000000..35dd1ac
--- /dev/null
+++ b/plugins/mm-modem-option-utils.c
@@ -0,0 +1,451 @@
+/* -*- 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 Option NV modems
+ * Used with both 'option' and 'hso'
+ ******************************************/
+
+#include "mm-callback-info.h"
+#include "mm-at-serial-port.h"
+#include "mm-generic-gsm.h"
+#include "mm-modem-helpers.h"
+
+static void
+option_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, "_OPSYS: ")) {
+ 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);
+}
+
+static void
+option_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, "AT_OPSYS?", 3, option_get_allowed_mode_done, info);
+}
+
+static void
+option_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
+option_set_allowed_mode (MMGenericGsm *gsm,
+ MMModemGsmAllowedMode mode,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
+ char *command;
+ int i;
+
+ 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:
+ 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 ("AT_OPSYS=%d,2", i);
+ mm_at_serial_port_queue_command (port, command, 3, option_set_allowed_mode_done, info);
+ g_free (command);
+}
+
+static gboolean
+octi_to_mm (char octi, MMModemGsmAccessTech *out_act)
+{
+ if (octi == '1') {
+ *out_act = MM_MODEM_GSM_ACCESS_TECH_GSM;
+ return TRUE;
+ } else if (octi == '2') {
+ *out_act = MM_MODEM_GSM_ACCESS_TECH_GPRS;
+ return TRUE;
+ } else if (octi == '3') {
+ *out_act = MM_MODEM_GSM_ACCESS_TECH_EDGE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+owcti_to_mm (char owcti, MMModemGsmAccessTech *out_act)
+{
+ if (owcti == '1') {
+ *out_act = MM_MODEM_GSM_ACCESS_TECH_UMTS;
+ return TRUE;
+ } else if (owcti == '2') {
+ *out_act = MM_MODEM_GSM_ACCESS_TECH_HSDPA;
+ return TRUE;
+ } else if (owcti == '3') {
+ *out_act = MM_MODEM_GSM_ACCESS_TECH_HSUPA;
+ return TRUE;
+ } else if (owcti == '4') {
+ *out_act = MM_MODEM_GSM_ACCESS_TECH_HSPA;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+parse_octi_response (GString *response, MMModemGsmAccessTech *act)
+{
+ MMModemGsmAccessTech cur_act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ const char *p;
+ GRegex *r;
+ GMatchInfo *match_info;
+ char *str;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (act != NULL, FALSE);
+ g_return_val_if_fail (response != NULL, FALSE);
+
+ p = mm_strip_tag (response->str, "_OCTI:");
+
+ r = g_regex_new ("(\\d),(\\d)", G_REGEX_UNGREEDY, 0, NULL);
+ g_return_val_if_fail (r != NULL, FALSE);
+
+ g_regex_match (r, p, 0, &match_info);
+ if (g_match_info_matches (match_info)) {
+ str = g_match_info_fetch (match_info, 2);
+ if (str && octi_to_mm (str[0], &cur_act)) {
+ *act = cur_act;
+ success = TRUE;
+ }
+ g_free (str);
+ }
+ g_match_info_free (match_info);
+ g_regex_unref (r);
+
+ return success;
+}
+
+static void
+ossys_octi_request_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+
+ if (!error) {
+ if (parse_octi_response (response, &act))
+ mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (user_data), act);
+ }
+}
+
+static void
+ossys_owcti_request_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ const char *p;
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+
+ if (!error) {
+ p = mm_strip_tag (response->str, "_OWCTI:");
+ if (owcti_to_mm (*p, &act))
+ mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (user_data), act);
+ }
+}
+
+static void
+option_ossys_tech_changed (MMAtSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data)
+{
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ char *str;
+
+ str = g_match_info_fetch (info, 1);
+ if (str) {
+ switch (atoi (str)) {
+ case 0:
+ act = MM_MODEM_GSM_ACCESS_TECH_GPRS;
+ break;
+ case 2:
+ act = MM_MODEM_GSM_ACCESS_TECH_UMTS;
+ break;
+ default:
+ break;
+ }
+ }
+ g_free (str);
+
+ mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (user_data), act);
+
+ /* _OSSYSI only indicates general 2G/3G mode, so queue up some explicit
+ * access technology requests.
+ */
+ if (act == MM_MODEM_GSM_ACCESS_TECH_GPRS)
+ mm_at_serial_port_queue_command (port, "_OCTI?", 3, ossys_octi_request_done, user_data);
+ else if (act == MM_MODEM_GSM_ACCESS_TECH_UMTS)
+ mm_at_serial_port_queue_command (port, "_OWCTI?", 3, ossys_owcti_request_done, user_data);
+}
+
+static void
+option_2g_tech_changed (MMAtSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data)
+{
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ char *str;
+
+ str = g_match_info_fetch (match_info, 1);
+ if (octi_to_mm (str[0], &act))
+ mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (user_data), act);
+ g_free (str);
+}
+
+static void
+option_3g_tech_changed (MMAtSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data)
+{
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ char *str;
+
+ str = g_match_info_fetch (match_info, 1);
+ if (owcti_to_mm (str[0], &act))
+ mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (user_data), act);
+ g_free (str);
+}
+
+static void
+option_signal_changed (MMAtSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data)
+{
+ char *str;
+ int quality = 0;
+
+ str = g_match_info_fetch (match_info, 1);
+ quality = atoi (str);
+ g_free (str);
+
+ if (quality == 99) {
+ /* 99 means unknown */
+ quality = 0;
+ } else {
+ /* Normalize the quality */
+ quality = CLAMP (quality, 0, 31) * 100 / 31;
+ }
+
+ mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (user_data), (guint32) quality);
+}
+
+static void
+option_register_unsolicted_handlers (MMGenericGsm *modem, MMAtSerialPort *port)
+{
+ GRegex *regex;
+
+ regex = g_regex_new ("\\r\\n_OSSYSI:\\s*(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (port, regex, option_ossys_tech_changed, modem, NULL);
+ g_regex_unref (regex);
+
+ regex = g_regex_new ("\\r\\n_OCTI:\\s*(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (port, regex, option_2g_tech_changed, modem, NULL);
+ g_regex_unref (regex);
+
+ regex = g_regex_new ("\\r\\n_OUWCTI:\\s*(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (port, regex, option_3g_tech_changed, modem, NULL);
+ g_regex_unref (regex);
+
+ regex = g_regex_new ("\\r\\n_OSIGQ:\\s*(\\d+),(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (port, regex, option_signal_changed, modem, NULL);
+ g_regex_unref (regex);
+}
+
+static void
+unsolicited_msg_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+
+ if (info)
+ mm_callback_info_chain_complete_one (info);
+}
+
+static void
+option_change_unsolicited_messages (MMGenericGsm *modem,
+ gboolean enabled,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = NULL;
+ MMAtSerialPort *primary;
+
+ if (callback) {
+ info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
+ mm_callback_info_chain_start (info, 4);
+ }
+
+ primary = mm_generic_gsm_get_at_port (modem, MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
+ mm_at_serial_port_queue_command (primary, enabled ? "_OSSYS=1" : "_OSSYS=0", 3, unsolicited_msg_done, info);
+ mm_at_serial_port_queue_command (primary, enabled ? "_OCTI=1" : "_OCTI=0", 3, unsolicited_msg_done, info);
+ mm_at_serial_port_queue_command (primary, enabled ? "_OUWCTI=1" : "_OUWCTI=0", 3, unsolicited_msg_done, info);
+ mm_at_serial_port_queue_command (primary, enabled ? "_OSQI=1" : "_OSQI=0", 3, unsolicited_msg_done, info);
+}
+
+static void
+get_act_octi_request_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ MMModemGsmAccessTech octi = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ MMModemGsmAccessTech owcti;
+
+ if (!error) {
+ if (parse_octi_response (response, &octi)) {
+ /* If no 3G tech yet or current tech isn't 3G, then 2G tech is the best */
+ owcti = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "owcti"));
+ if (octi && !owcti)
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (octi), NULL);
+ }
+ }
+
+ mm_callback_info_chain_complete_one (info);
+}
+
+static void
+get_act_owcti_request_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ MMModemGsmAccessTech owcti = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ const char *p;
+
+ if (!error) {
+ p = mm_strip_tag (response->str, "_OWCTI:");
+ if (owcti_to_mm (*p, &owcti)) {
+ /* 3G tech always takes precedence over 2G tech */
+ if (owcti)
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (owcti), NULL);
+ }
+ }
+
+ mm_callback_info_chain_complete_one (info);
+}
+
+static void
+option_get_access_technology (MMGenericGsm *modem,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMAtSerialPort *port;
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
+ mm_callback_info_chain_start (info, 2);
+
+ port = mm_generic_gsm_get_best_at_port (modem, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (port, "_OCTI?", 3, get_act_octi_request_done, info);
+ mm_at_serial_port_queue_command (port, "_OWCTI?", 3, get_act_owcti_request_done, info);
+}
+
diff --git a/plugins/mm-modem-option.c b/plugins/mm-modem-option.c
index 2076ae6..ac04b0b 100644
--- a/plugins/mm-modem-option.c
+++ b/plugins/mm-modem-option.c
@@ -23,12 +23,15 @@
#include "mm-callback-info.h"
static void modem_init (MMModem *modem_class);
-static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class);
G_DEFINE_TYPE_EXTENDED (MMModemOption, mm_modem_option, MM_TYPE_GENERIC_GSM, 0,
- G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)
- G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_NETWORK, modem_gsm_network_init))
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init))
+#define MM_MODEM_OPTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_OPTION, MMModemOptionPrivate))
+
+typedef struct {
+ guint enable_wait_id;
+} MMModemOptionPrivate;
MMModem *
mm_modem_option_new (const char *device,
@@ -46,174 +49,156 @@ mm_modem_option_new (const char *device,
NULL));
}
+#include "mm-modem-option-utils.c"
+
/*****************************************************************************/
-static void
-pin_check_done (MMModem *modem, GError *error, gpointer user_data)
+static gboolean
+option_enabled (gpointer user_data)
{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMCallbackInfo *info = user_data;
+ MMGenericGsm *modem;
+ MMModemOptionPrivate *priv;
- mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info);
-}
+ /* Make sure we don't use an invalid modem that may have been removed */
+ if (info->modem) {
+ modem = MM_GENERIC_GSM (info->modem);
+ priv = MM_MODEM_OPTION_GET_PRIVATE (modem);
+ priv->enable_wait_id = 0;
-static gboolean
-option_enabled (gpointer data)
-{
- MMCallbackInfo *info = (MMCallbackInfo *) data;
+ option_change_unsolicited_messages (modem, TRUE, NULL, NULL);
- /* Now check the PIN explicitly, option doesn't seem to report
- * that it needs it otherwise.
- */
- mm_generic_gsm_check_pin (MM_GENERIC_GSM (info->modem), pin_check_done, info);
+ MM_GENERIC_GSM_CLASS (mm_modem_option_parent_class)->do_enable_power_up_done (modem, NULL, NULL, info);
+ }
return FALSE;
}
static void
-parent_enable_done (MMModem *modem, GError *error, gpointer user_data)
+real_do_enable_power_up_done (MMGenericGsm *gsm,
+ GString *response,
+ GError *error,
+ MMCallbackInfo *info)
{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemOptionPrivate *priv = MM_MODEM_OPTION_GET_PRIVATE (gsm);
if (error) {
- mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info);
+ /* Chain up to parent */
+ MM_GENERIC_GSM_CLASS (mm_modem_option_parent_class)->do_enable_power_up_done (gsm, NULL, error, info);
return;
}
- /* Option returns OK on +CFUN=1 right away but needs some time
- * to finish initialization
+ /* Some Option devices return OK on +CFUN=1 right away but need some time
+ * to finish initialization.
*/
- g_timeout_add_seconds (10, option_enabled, info);
+ g_warn_if_fail (priv->enable_wait_id == 0);
+ priv->enable_wait_id = g_timeout_add_seconds (10, option_enabled, info);
}
+/*****************************************************************************/
+
static void
-enable (MMModem *modem,
- MMModemFn callback,
- gpointer user_data)
+get_allowed_mode (MMGenericGsm *gsm,
+ MMModemUIntFn callback,
+ gpointer user_data)
{
- MMModem *parent_modem_iface;
- MMCallbackInfo *info;
+ option_get_allowed_mode (gsm, callback, user_data);
+}
- info = mm_callback_info_new (modem, callback, user_data);
- parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem));
- parent_modem_iface->enable (modem, parent_enable_done, info);
+static void
+set_allowed_mode (MMGenericGsm *gsm,
+ MMModemGsmAllowedMode mode,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ option_set_allowed_mode (gsm, mode, callback, user_data);
}
static void
-get_network_mode_done (MMSerialPort *port,
- GString *response,
- GError *error,
+get_access_technology (MMGenericGsm *gsm,
+ MMModemUIntFn callback,
gpointer user_data)
{
+ option_get_access_technology (gsm, callback, user_data);
+}
+
+/*****************************************************************************/
+
+static void
+parent_disable_done (MMModem *modem, 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, "_OPSYS: ")) {
- int a, b;
-
- if (sscanf (response->str + 8, "%d,%d", &a, &b)) {
- MMModemGsmMode mode = MM_MODEM_GSM_MODE_ANY;
-
- switch (a) {
- case 0:
- mode = MM_MODEM_GSM_MODE_2G_ONLY;
- break;
- case 1:
- mode = MM_MODEM_GSM_MODE_3G_ONLY;
- break;
- case 2:
- mode = MM_MODEM_GSM_MODE_2G_PREFERRED;
- break;
- case 3:
- mode = MM_MODEM_GSM_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 network mode results");
-
mm_callback_info_schedule (info);
}
static void
-get_network_mode (MMModemGsmNetwork *modem,
- MMModemUIntFn callback,
- gpointer user_data)
+unsolicited_disable_done (MMModem *modem,
+ GError *error,
+ gpointer user_data)
{
- MMCallbackInfo *info;
- MMSerialPort *primary;
+ MMCallbackInfo *info = user_data;
+ MMModem *parent_modem_iface;
+ GError *tmp_error = NULL;
+
+ /* Handle modem removal, but ignore other errors */
+ if (g_error_matches (error, MM_MODEM_ERROR, MM_MODEM_ERROR_REMOVED)) {
+ parent_disable_done (modem, error, user_data);
+ return;
+ } else if (!modem) {
+ tmp_error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_REMOVED,
+ "The modem was removed.");
+ parent_disable_done (modem, tmp_error, user_data);
+ g_error_free (tmp_error);
+ return;
+ }
- info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
- mm_serial_port_queue_command (primary, "AT_OPSYS?", 3, get_network_mode_done, info);
+ /* Chain up to parent */
+ parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem));
+ parent_modem_iface->disable (info->modem, parent_disable_done, info);
}
static void
-set_network_mode_done (MMSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
+disable (MMModem *modem,
+ MMModemFn callback,
+ gpointer user_data)
{
- MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMCallbackInfo *info;
- if (error)
- info->error = g_error_copy (error);
-
- mm_callback_info_schedule (info);
+ mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (modem));
+
+ info = mm_callback_info_new (modem, callback, user_data);
+
+ /* Turn off unsolicited messages so they don't pile up in the modem */
+ option_change_unsolicited_messages (MM_GENERIC_GSM (modem), FALSE, unsolicited_disable_done, info);
}
-static void
-set_network_mode (MMModemGsmNetwork *modem,
- MMModemGsmMode mode,
- MMModemFn callback,
- gpointer user_data)
+static gboolean
+grab_port (MMModem *modem,
+ const char *subsys,
+ const char *name,
+ MMPortType suggested_type,
+ gpointer user_data,
+ GError **error)
{
- MMCallbackInfo *info;
- MMSerialPort *primary;
- char *command;
- int i;
-
- info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
-
- switch (mode) {
- case MM_MODEM_GSM_MODE_ANY:
- case MM_MODEM_GSM_MODE_GPRS:
- case MM_MODEM_GSM_MODE_EDGE:
- case MM_MODEM_GSM_MODE_2G_ONLY:
- i = 0;
- break;
- case MM_MODEM_GSM_MODE_UMTS:
- case MM_MODEM_GSM_MODE_HSDPA:
- case MM_MODEM_GSM_MODE_HSUPA:
- case MM_MODEM_GSM_MODE_HSPA:
- case MM_MODEM_GSM_MODE_3G_ONLY:
- i = 1;
- break;
- case MM_MODEM_GSM_MODE_2G_PREFERRED:
- i = 2;
- break;
- case MM_MODEM_GSM_MODE_3G_PREFERRED:
- i = 3;
- break;
- default:
- i = 5;
- break;
+ MMGenericGsm *gsm = MM_GENERIC_GSM (modem);
+ MMPort *port = NULL;
+
+ port = mm_generic_gsm_grab_port (gsm, subsys, name, suggested_type, error);
+ if (port && MM_IS_AT_SERIAL_PORT (port)) {
+ if (mm_port_get_port_type (port) == MM_PORT_TYPE_PRIMARY) {
+ GRegex *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);
+ }
+ option_register_unsolicted_handlers (gsm, MM_AT_SERIAL_PORT (port));
}
- command = g_strdup_printf ("AT_OPSYS=%d,2", i);
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
- mm_serial_port_queue_command (primary, command, 3, set_network_mode_done, info);
- g_free (command);
+ return !!port;
}
/*****************************************************************************/
@@ -221,24 +206,37 @@ set_network_mode (MMModemGsmNetwork *modem,
static void
modem_init (MMModem *modem_class)
{
- modem_class->enable = enable;
+ modem_class->disable = disable;
+ modem_class->grab_port = grab_port;
}
static void
-modem_gsm_network_init (MMModemGsmNetwork *class)
+mm_modem_option_init (MMModemOption *self)
{
- class->set_network_mode = set_network_mode;
- class->get_network_mode = get_network_mode;
}
static void
-mm_modem_option_init (MMModemOption *self)
+dispose (GObject *object)
{
+ MMModemOptionPrivate *priv = MM_MODEM_OPTION_GET_PRIVATE (object);
+
+ if (priv->enable_wait_id)
+ g_source_remove (priv->enable_wait_id);
}
static void
mm_modem_option_class_init (MMModemOptionClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
+
mm_modem_option_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (object_class, sizeof (MMModemOptionPrivate));
+
+ object_class->dispose = dispose;
+ gsm_class->do_enable_power_up_done = real_do_enable_power_up_done;
+ 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-sierra-cdma.c b/plugins/mm-modem-sierra-cdma.c
index 4f3140b..fc62bf6 100644
--- a/plugins/mm-modem-sierra-cdma.c
+++ b/plugins/mm-modem-sierra-cdma.c
@@ -28,6 +28,7 @@
#include "mm-callback-info.h"
#include "mm-serial-port.h"
#include "mm-serial-parsers.h"
+#include "mm-modem-helpers.h"
G_DEFINE_TYPE (MMModemSierraCdma, mm_modem_sierra_cdma, MM_TYPE_GENERIC_CDMA)
@@ -75,13 +76,19 @@ mm_modem_sierra_cdma_new (const char *device,
#define SYS_MODE_NO_SERVICE_TAG "NO SRV"
#define SYS_MODE_EVDO_TAG "HDR"
#define SYS_MODE_1X_TAG "1x"
+#define SYS_MODE_CDMA_TAG "CDMA"
#define EVDO_REV_TAG "HDR Revision:"
#define SID_TAG "SID:"
static gboolean
-get_roam_value (const char *reply, const char *tag, gboolean *roaming)
+get_roam_value (const char *reply,
+ const char *tag,
+ gboolean is_eri,
+ gboolean *out_roaming)
{
char *p;
+ gboolean success;
+ guint32 ind = 0;
p = strstr (reply, tag);
if (!p)
@@ -90,11 +97,26 @@ get_roam_value (const char *reply, const char *tag, gboolean *roaming)
p += strlen (tag);
while (*p && isspace (*p))
p++;
+
+ /* Use generic ERI parsing if it's an ERI */
+ if (is_eri) {
+ success = mm_cdma_parse_eri (p, out_roaming, &ind, NULL);
+ if (success) {
+ /* Sierra redefines ERI 0, 1, and 2 */
+ if (ind == 0)
+ *out_roaming = FALSE; /* home */
+ else if (ind == 1 || ind == 2)
+ *out_roaming = TRUE; /* roaming */
+ }
+ return success;
+ }
+
+ /* If it's not an ERI, roaming is just true/false */
if (*p == '1') {
- *roaming = TRUE;
+ *out_roaming = TRUE;
return TRUE;
} else if (*p == '0') {
- *roaming = FALSE;
+ *out_roaming = FALSE;
return TRUE;
}
@@ -109,8 +131,14 @@ sys_mode_has_service (SysMode mode)
|| mode == SYS_MODE_EVDO_REVA);
}
+static gboolean
+sys_mode_is_evdo (SysMode mode)
+{
+ return (mode == SYS_MODE_EVDO_REV0 || mode == SYS_MODE_EVDO_REVA);
+}
+
static void
-status_done (MMSerialPort *port,
+status_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -122,16 +150,16 @@ status_done (MMSerialPort *port,
gboolean have_sid = FALSE;
SysMode evdo_mode = SYS_MODE_UNKNOWN;
SysMode sys_mode = SYS_MODE_UNKNOWN;
- gboolean cdma_1x_set = FALSE, evdo_set = FALSE;
+ gboolean evdo_roam = FALSE, cdma1x_roam = FALSE;
if (error) {
- info->error = g_error_copy (error);
+ /* Leave superclass' reg state alone if AT!STATUS isn't supported */
goto done;
}
lines = g_strsplit_set (response->str, "\n\r", 0);
if (!lines) {
- /* Whatever, just use default registration state */
+ /* Whatever, just use superclass' registration state */
goto done;
}
@@ -197,29 +225,10 @@ status_done (MMSerialPort *port,
}
/* Roaming */
- if (get_roam_value (*iter, ROAM_1X_TAG, &bool_val)) {
- mm_generic_cdma_query_reg_state_set_callback_1x_state (info,
- bool_val ? MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING :
- MM_MODEM_CDMA_REGISTRATION_STATE_HOME);
- cdma_1x_set = TRUE;
- }
- if (get_roam_value (*iter, ROAM_EVDO_TAG, &bool_val)) {
- mm_generic_cdma_query_reg_state_set_callback_evdo_state (info,
- bool_val ? MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING :
- MM_MODEM_CDMA_REGISTRATION_STATE_HOME);
- evdo_set = TRUE;
- }
- if (get_roam_value (*iter, GENERIC_ROAM_TAG, &bool_val)) {
- MMModemCdmaRegistrationState reg_state;
-
- reg_state = bool_val ? MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING :
- MM_MODEM_CDMA_REGISTRATION_STATE_HOME;
-
- mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state);
- mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, reg_state);
- cdma_1x_set = TRUE;
- evdo_set = TRUE;
- }
+ get_roam_value (*iter, ROAM_1X_TAG, TRUE, &cdma1x_roam);
+ get_roam_value (*iter, ROAM_EVDO_TAG, TRUE, &evdo_roam);
+ if (get_roam_value (*iter, GENERIC_ROAM_TAG, FALSE, &bool_val))
+ cdma1x_roam = evdo_roam = bool_val;
/* Current system mode */
p = strstr (*iter, SYS_MODE_TAG);
@@ -231,7 +240,8 @@ status_done (MMSerialPort *port,
sys_mode = SYS_MODE_NO_SERVICE;
else if (!strncmp (p, SYS_MODE_EVDO_TAG, strlen (SYS_MODE_EVDO_TAG)))
sys_mode = SYS_MODE_EVDO_REV0;
- else if (!strncmp (p, SYS_MODE_1X_TAG, strlen (SYS_MODE_1X_TAG)))
+ else if ( !strncmp (p, SYS_MODE_1X_TAG, strlen (SYS_MODE_1X_TAG))
+ || !strncmp (p, SYS_MODE_CDMA_TAG, strlen (SYS_MODE_CDMA_TAG)))
sys_mode = SYS_MODE_CDMA_1X;
}
@@ -259,24 +269,36 @@ status_done (MMSerialPort *port,
}
/* Update current system mode */
- if (sys_mode == SYS_MODE_EVDO_REV0 || sys_mode == SYS_MODE_EVDO_REVA) {
+ if (sys_mode_is_evdo (sys_mode)) {
/* Prefer the explicit EVDO mode from EVDO_REV_TAG */
if (evdo_mode != SYS_MODE_UNKNOWN)
sys_mode = evdo_mode;
}
priv->sys_mode = sys_mode;
- if (registered || have_sid || sys_mode_has_service (sys_mode)) {
- /* As a backup, if for some reason the registration states didn't get
- * figured out by parsing the status info, set some generic registration
- * states here.
- */
- if (!cdma_1x_set)
- mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED);
-
- /* Ensure EVDO registration mode is set if we're at least in EVDO mode */
- if (!evdo_set && (sys_mode == SYS_MODE_EVDO_REV0 || sys_mode == SYS_MODE_EVDO_REVA))
- mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED);
+ /* If the modem didn't report explicit registration with "Modem has
+ * registered" then get registration status by looking at either system
+ * mode or (for older devices that don't report that) just the SID.
+ */
+ if (!registered) {
+ if (sys_mode != SYS_MODE_UNKNOWN)
+ registered = sys_mode_has_service (sys_mode);
+ else
+ registered = have_sid;
+ }
+
+ if (registered) {
+ mm_generic_cdma_query_reg_state_set_callback_1x_state (info,
+ cdma1x_roam ? MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING :
+ MM_MODEM_CDMA_REGISTRATION_STATE_HOME);
+
+ if (sys_mode_is_evdo (sys_mode)) {
+ mm_generic_cdma_query_reg_state_set_callback_evdo_state (info,
+ evdo_roam ? MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING :
+ MM_MODEM_CDMA_REGISTRATION_STATE_HOME);
+ } else {
+ mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
+ }
} else {
/* Not registered */
mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
@@ -289,35 +311,27 @@ done:
static void
query_registration_state (MMGenericCdma *cdma,
+ MMModemCdmaRegistrationState cur_cdma_state,
+ MMModemCdmaRegistrationState cur_evdo_state,
MMModemCdmaRegistrationStateFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
- MMSerialPort *primary, *secondary;
- MMSerialPort *port;
-
- port = primary = mm_generic_cdma_get_port (cdma, MM_PORT_TYPE_PRIMARY);
- secondary = mm_generic_cdma_get_port (cdma, MM_PORT_TYPE_SECONDARY);
+ MMAtSerialPort *port;
- info = mm_generic_cdma_query_reg_state_callback_info_new (cdma, callback, user_data);
-
- if (mm_port_get_connected (MM_PORT (primary))) {
- if (!secondary) {
- info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_CONNECTED,
- "Cannot get query registration state while connected");
- mm_callback_info_schedule (info);
- return;
- }
+ info = mm_generic_cdma_query_reg_state_callback_info_new (cdma, cur_cdma_state, cur_evdo_state, callback, user_data);
- /* Use secondary port if primary is connected */
- port = secondary;
+ port = mm_generic_cdma_get_best_at_port (cdma, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
}
- mm_serial_port_queue_command (port, "!STATUS", 3, status_done, info);
+ mm_at_serial_port_queue_command (port, "!STATUS", 3, status_done, info);
}
static void
-pcstate_done (MMSerialPort *port,
+pcstate_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -334,14 +348,14 @@ post_enable (MMGenericCdma *cdma,
gpointer user_data)
{
MMCallbackInfo *info;
- MMSerialPort *primary;
+ MMAtSerialPort *primary;
info = mm_callback_info_new (MM_MODEM (cdma), callback, user_data);
- primary = mm_generic_cdma_get_port (cdma, MM_PORT_TYPE_PRIMARY);
+ primary = mm_generic_cdma_get_at_port (cdma, MM_PORT_TYPE_PRIMARY);
g_assert (primary);
- mm_serial_port_queue_command (primary, "!pcstate=1", 5, pcstate_done, info);
+ mm_at_serial_port_queue_command (primary, "!pcstate=1", 5, pcstate_done, info);
}
static void
@@ -350,14 +364,14 @@ post_disable (MMGenericCdma *cdma,
gpointer user_data)
{
MMCallbackInfo *info;
- MMSerialPort *primary;
+ MMAtSerialPort *primary;
info = mm_callback_info_new (MM_MODEM (cdma), callback, user_data);
- primary = mm_generic_cdma_get_port (cdma, MM_PORT_TYPE_PRIMARY);
+ primary = mm_generic_cdma_get_at_port (cdma, MM_PORT_TYPE_PRIMARY);
g_assert (primary);
- mm_serial_port_queue_command (primary, "!pcstate=0", 5, pcstate_done, info);
+ mm_at_serial_port_queue_command (primary, "!pcstate=0", 5, pcstate_done, info);
}
/*****************************************************************************/
diff --git a/plugins/mm-modem-sierra-gsm.c b/plugins/mm-modem-sierra-gsm.c
index ee82234..bf5df31 100644
--- a/plugins/mm-modem-sierra-gsm.c
+++ b/plugins/mm-modem-sierra-gsm.c
@@ -11,9 +11,10 @@
* 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 <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -21,12 +22,18 @@
#include "mm-modem-sierra-gsm.h"
#include "mm-errors.h"
#include "mm-callback-info.h"
+#include "mm-modem-helpers.h"
static void modem_init (MMModem *modem_class);
G_DEFINE_TYPE_EXTENDED (MMModemSierraGsm, mm_modem_sierra_gsm, MM_TYPE_GENERIC_GSM, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_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;
+} MMModemSierraGsmPrivate;
MMModem *
mm_modem_sierra_gsm_new (const char *device,
@@ -45,54 +52,232 @@ mm_modem_sierra_gsm_new (const char *device,
}
/*****************************************************************************/
-/* Modem class override functions */
-/*****************************************************************************/
static void
-pin_check_done (MMModem *modem, GError *error, gpointer user_data)
+get_allowed_mode_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ GRegex *r = NULL;
+ GMatchInfo *match_info;
+
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (info->error)
+ goto done;
+
+ /* Example response: !SELRAT: 03, UMTS 3G Preferred */
+ r = g_regex_new ("!SELRAT:\\s*(\\d+).*$", 0, 0, NULL);
+ if (!r) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Failed to parse the allowed mode response");
+ goto done;
+ }
+
+ if (g_regex_match_full (r, response->str, response->len, 0, 0, &match_info, &info->error)) {
+ MMModemGsmAllowedMode mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+ char *str;
+
+ str = g_match_info_fetch (match_info, 1);
+ switch (atoi (str)) {
+ case 0:
+ mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+ break;
+ case 1:
+ mode = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY;
+ break;
+ case 2:
+ mode = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY;
+ break;
+ case 3:
+ mode = MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED;
+ break;
+ case 4:
+ mode = MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED;
+ break;
+ default:
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Failed to parse the allowed mode response: '%s'",
+ response->str);
+ break;
+ }
+ g_free (str);
+
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mode), NULL);
+ }
- mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info);
+done:
+ if (r)
+ g_regex_unref (r);
+ mm_callback_info_schedule (info);
}
-static gboolean
-sierra_enabled (gpointer data)
+static void
+get_allowed_mode (MMGenericGsm *gsm,
+ MMModemUIntFn callback,
+ gpointer user_data)
{
- MMCallbackInfo *info = (MMCallbackInfo *) data;
+ MMCallbackInfo *info;
+ MMAtSerialPort *primary;
- /* Now check the PIN explicitly, sierra doesn't seem to report
- * that it needs it otherwise.
- */
- mm_generic_gsm_check_pin (MM_GENERIC_GSM (info->modem), pin_check_done, info);
- return FALSE;
+ info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data);
+
+ /* Sierra secondary ports don't have full AT command interpreters */
+ primary = mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY);
+ if (!primary || mm_port_get_connected (MM_PORT (primary))) {
+ g_set_error_literal (&info->error, MM_MODEM_ERROR, MM_MODEM_ERROR_CONNECTED,
+ "Cannot perform this operation while connected");
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (primary, "!SELRAT?", 3, get_allowed_mode_done, info);
}
static void
-parent_enable_done (MMModem *modem, GError *error, gpointer user_data)
+set_allowed_mode_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- if (error) {
- mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info);
+ 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;
+ MMAtSerialPort *primary;
+ char *command;
+ int idx = 0;
+
+ info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data);
+
+ /* Sierra secondary ports don't have full AT command interpreters */
+ primary = mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY);
+ if (!primary || mm_port_get_connected (MM_PORT (primary))) {
+ g_set_error_literal (&info->error, MM_MODEM_ERROR, MM_MODEM_ERROR_CONNECTED,
+ "Cannot perform this operation while connected");
+ mm_callback_info_schedule (info);
return;
}
- /* Sierra returns OK on +CFUN=1 right away but needs some time
- * to finish initialization.
- */
- g_timeout_add_seconds (10, sierra_enabled, info);
+ switch (mode) {
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY:
+ idx = 2;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY:
+ idx = 1;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED:
+ idx = 4;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED:
+ idx = 3;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_ANY:
+ default:
+ break;
+ }
+
+ command = g_strdup_printf ("!SELRAT=%d", idx);
+ mm_at_serial_port_queue_command (primary, command, 3, set_allowed_mode_done, info);
+ g_free (command);
}
static void
-enable (MMModem *modem, MMModemFn callback, gpointer user_data)
+get_act_request_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
- MMModem *parent_modem_iface;
+ MMCallbackInfo *info = user_data;
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ const char *p;
+
+ if (error)
+ info->error = g_error_copy (error);
+ else {
+ p = mm_strip_tag (response->str, "*CNTI:");
+ p = strchr (p, ',');
+ if (p)
+ act = mm_gsm_string_to_access_tech (p + 1);
+ }
+
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (act), NULL);
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_access_technology (MMGenericGsm *modem,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMAtSerialPort *port;
MMCallbackInfo *info;
- info = mm_callback_info_new (modem, callback, user_data);
- parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem));
- parent_modem_iface->enable (modem, parent_enable_done, info);
+ info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (modem, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (port, "*CNTI=0", 3, get_act_request_done, info);
+}
+
+/*****************************************************************************/
+/* Modem class override functions */
+/*****************************************************************************/
+
+static gboolean
+sierra_enabled (gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ MMGenericGsm *modem;
+ MMModemSierraGsmPrivate *priv;
+
+ /* Make sure we don't use an invalid modem that may have been removed */
+ if (info->modem) {
+ modem = MM_GENERIC_GSM (info->modem);
+ priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (modem);
+ priv->enable_wait_id = 0;
+ MM_GENERIC_GSM_CLASS (mm_modem_sierra_gsm_parent_class)->do_enable_power_up_done (modem, NULL, NULL, info);
+ }
+ return FALSE;
+}
+
+static void
+real_do_enable_power_up_done (MMGenericGsm *gsm,
+ GString *response,
+ GError *error,
+ MMCallbackInfo *info)
+{
+ MMModemSierraGsmPrivate *priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (gsm);
+
+ if (error) {
+ /* Chain up to parent */
+ MM_GENERIC_GSM_CLASS (mm_modem_sierra_gsm_parent_class)->do_enable_power_up_done (gsm, NULL, error, info);
+ return;
+ }
+
+ /* Some Sierra devices return OK on +CFUN=1 right away but need some time
+ * to finish initialization.
+ */
+ g_warn_if_fail (priv->enable_wait_id == 0);
+ priv->enable_wait_id = g_timeout_add_seconds (10, sierra_enabled, info);
}
static gboolean
@@ -108,18 +293,25 @@ grab_port (MMModem *modem,
MMPort *port;
if (suggested_type == MM_PORT_TYPE_UNKNOWN) {
- if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY))
+ if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY))
ptype = MM_PORT_TYPE_PRIMARY;
- else if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_SECONDARY))
+ 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_SERIAL_PORT (port))
+ if (port && MM_IS_AT_SERIAL_PORT (port)) {
+ GRegex *regex;
+
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);
+ }
+
return !!port;
}
@@ -128,7 +320,6 @@ grab_port (MMModem *modem,
static void
modem_init (MMModem *modem_class)
{
- modem_class->enable = enable;
modem_class->grab_port = grab_port;
}
@@ -138,8 +329,27 @@ mm_modem_sierra_gsm_init (MMModemSierraGsm *self)
}
static void
+dispose (GObject *object)
+{
+ MMModemSierraGsmPrivate *priv = MM_MODEM_SIERRA_GSM_GET_PRIVATE (object);
+
+ if (priv->enable_wait_id)
+ g_source_remove (priv->enable_wait_id);
+}
+
+static void
mm_modem_sierra_gsm_class_init (MMModemSierraGsmClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
+
mm_modem_sierra_gsm_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (object_class, sizeof (MMModemSierraGsmPrivate));
+
+ object_class->dispose = dispose;
+ gsm_class->do_enable_power_up_done = real_do_enable_power_up_done;
+ 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-simtech-gsm.c b/plugins/mm-modem-simtech-gsm.c
new file mode 100644
index 0000000..07820b3
--- /dev/null
+++ b/plugins/mm-modem-simtech-gsm.c
@@ -0,0 +1,471 @@
+/* -*- 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-simtech-gsm.h"
+#include "mm-at-serial-port.h"
+#include "mm-errors.h"
+#include "mm-callback-info.h"
+#include "mm-modem-helpers.h"
+
+static void modem_init (MMModem *modem_class);
+
+G_DEFINE_TYPE_EXTENDED (MMModemSimtechGsm, mm_modem_simtech_gsm, MM_TYPE_GENERIC_GSM, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init))
+
+MMModem *
+mm_modem_simtech_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin)
+{
+ 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_SIMTECH_GSM,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ NULL));
+}
+
+/*****************************************************************************/
+
+#define ACQ_ORDER_TAG "acq-order"
+
+static void
+get_mode_pref_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ const char *p;
+ gint modepref = -1;
+ guint32 acqord;
+ MMModemGsmAllowedMode allowed = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (info->error)
+ goto done;
+
+ p = mm_strip_tag (response->str, "+CNMP:");
+ if (!p) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Failed to parse the mode preference response");
+ goto done;
+ }
+
+ acqord = GPOINTER_TO_UINT (mm_callback_info_get_data (info, ACQ_ORDER_TAG));
+ modepref = atoi (p);
+
+ if (modepref == 2) {
+ /* Automatic */
+ if (acqord == 0)
+ allowed = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+ else if (acqord == 1)
+ allowed = MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED;
+ else if (acqord == 2)
+ allowed = MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED;
+ else {
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Unknown acqisition order preference %d",
+ acqord);
+ }
+ } else if (modepref == 13) {
+ /* GSM only */
+ allowed = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY;
+ } else if (modepref == 14) {
+ /* WCDMA only */
+ allowed = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY;
+ } else {
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Unknown mode preference %d",
+ modepref);
+ }
+
+done:
+ if (!info->error)
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (allowed), NULL);
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_acq_order_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ const char *p;
+ gint acqord = -1;
+
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (info->error)
+ goto done;
+
+ p = mm_strip_tag (response->str, "+CNAOP:");
+ if (!p) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Failed to parse the acqisition order response");
+ goto done;
+ }
+
+ acqord = atoi (p);
+ if (acqord < 0 || acqord > 2) {
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Unknown acquisition order response %d",
+ acqord);
+ } else {
+ /* Cache the acquisition preference */
+ mm_callback_info_set_data (info, ACQ_ORDER_TAG, GUINT_TO_POINTER (acqord), NULL);
+ }
+
+done:
+ if (info->error)
+ mm_callback_info_schedule (info);
+ else
+ mm_at_serial_port_queue_command (port, "+CNMP?", 3, get_mode_pref_done, 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, "+CNAOP?", 3, get_acq_order_done, info);
+}
+
+static void
+set_acq_order_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_mode_pref_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ guint32 naop;
+ char *command;
+
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (info->error) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ naop = GPOINTER_TO_UINT (mm_callback_info_get_data (info, ACQ_ORDER_TAG));
+ command = g_strdup_printf ("+CNAOP=%u", naop);
+ mm_at_serial_port_queue_command (port, command, 3, set_acq_order_done, info);
+ g_free (command);
+}
+
+static void
+set_allowed_mode (MMGenericGsm *gsm,
+ MMModemGsmAllowedMode mode,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMAtSerialPort *port;
+ char *command;
+ guint32 nmp = 2; /* automatic mode preference */
+ guint32 naop = 0; /* automatic acquisition order */
+
+ 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:
+ nmp = 13;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY:
+ nmp = 14;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED:
+ naop = 2;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED:
+ naop = 3;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_ANY:
+ default:
+ break;
+ }
+
+ mm_callback_info_set_data (info, ACQ_ORDER_TAG, GUINT_TO_POINTER (naop), NULL);
+
+ command = g_strdup_printf ("+CNMP=%u", nmp);
+ mm_at_serial_port_queue_command (port, command, 3, set_mode_pref_done, info);
+ g_free (command);
+}
+
+static MMModemGsmAccessTech
+simtech_act_to_mm_act (int nsmod)
+{
+ if (nsmod == 1)
+ return MM_MODEM_GSM_ACCESS_TECH_GSM;
+ else if (nsmod == 2)
+ return MM_MODEM_GSM_ACCESS_TECH_GPRS;
+ else if (nsmod == 3)
+ return MM_MODEM_GSM_ACCESS_TECH_EDGE;
+ else if (nsmod == 4)
+ return MM_MODEM_GSM_ACCESS_TECH_UMTS;
+ else if (nsmod == 5)
+ return MM_MODEM_GSM_ACCESS_TECH_HSDPA;
+ else if (nsmod == 6)
+ return MM_MODEM_GSM_ACCESS_TECH_HSUPA;
+ else if (nsmod == 7)
+ return MM_MODEM_GSM_ACCESS_TECH_HSPA;
+
+ return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+}
+
+static void
+get_act_tech_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ const char *p;
+
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (info->error) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ p = mm_strip_tag (response->str, "+CNSMOD:");
+ if (p)
+ p = strchr (p, ',');
+
+ if (!p || !isdigit (*(p + 1))) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Failed to parse the access technology response");
+ } else {
+ act = simtech_act_to_mm_act (atoi (p + 1));
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (act), NULL);
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_access_technology (MMGenericGsm *modem,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMAtSerialPort *port;
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (modem, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (port, "AT+CNSMOD?", 3, get_act_tech_done, info);
+}
+
+static void
+handle_act_change (MMAtSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data)
+{
+ MMModemSimtechGsm *self = MM_MODEM_SIMTECH_GSM (user_data);
+ MMModemGsmAccessTech act;
+ char *str;
+
+ str = g_match_info_fetch (match_info, 1);
+ if (str && strlen (str)) {
+ act = simtech_act_to_mm_act (atoi (str));
+ mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (self), act);
+ }
+ g_free (str);
+}
+
+/*****************************************************************************/
+
+static void
+real_do_enable_power_up_done (MMGenericGsm *gsm,
+ GString *response,
+ GError *error,
+ MMCallbackInfo *info)
+{
+ if (!error) {
+ MMAtSerialPort *primary;
+
+ /* Enable unsolicited result codes */
+ primary = mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
+ /* Autoreport access technology changes */
+ mm_at_serial_port_queue_command (primary, "+CNSMOD=1", 5, NULL, NULL);
+
+ /* Autoreport CSQ (first arg), and only report when it changes (second arg) */
+ mm_at_serial_port_queue_command (primary, "+AUTOCSQ=1,1", 5, NULL, NULL);
+ }
+
+ /* Chain up to parent */
+ MM_GENERIC_GSM_CLASS (mm_modem_simtech_gsm_parent_class)->do_enable_power_up_done (gsm, NULL, error, 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)
+{
+ MMAtSerialPort *primary;
+ DisableInfo *info;
+
+ 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 */
+ mm_at_serial_port_queue_command (primary, "+CNSMOD=0;+AUTOCSQ=0", 5, disable_unsolicited_done, info);
+}
+
+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;
+
+ 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)) {
+ GRegex *regex;
+
+ regex = g_regex_new ("\\r\\n\\+CNSMOD:\\s*(\\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, handle_act_change, modem, NULL);
+ g_regex_unref (regex);
+ }
+
+ return !!port;
+}
+
+/*****************************************************************************/
+
+static void
+modem_init (MMModem *modem_class)
+{
+ modem_class->disable = disable;
+ modem_class->grab_port = grab_port;
+}
+
+static void
+mm_modem_simtech_gsm_init (MMModemSimtechGsm *self)
+{
+}
+
+static void
+mm_modem_simtech_gsm_class_init (MMModemSimtechGsmClass *klass)
+{
+ MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
+
+ mm_modem_simtech_gsm_parent_class = g_type_class_peek_parent (klass);
+
+ gsm_class->do_enable_power_up_done = real_do_enable_power_up_done;
+ 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-simtech-gsm.h b/plugins/mm-modem-simtech-gsm.h
new file mode 100644
index 0000000..0ba3c43
--- /dev/null
+++ b/plugins/mm-modem-simtech-gsm.h
@@ -0,0 +1,43 @@
+/* -*- 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_SIMTECH_GSM_H
+#define MM_MODEM_SIMTECH_GSM_H
+
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_SIMTECH_GSM (mm_modem_simtech_gsm_get_type ())
+#define MM_MODEM_SIMTECH_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_SIMTECH_GSM, MMModemSimtechGsm))
+#define MM_MODEM_SIMTECH_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_SIMTECH_GSM, MMModemSimtechGsmClass))
+#define MM_IS_MODEM_SIMTECH_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_SIMTECH_GSM))
+#define MM_IS_MODEM_SIMTECH_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_SIMTECH_GSM))
+#define MM_MODEM_SIMTECH_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_SIMTECH_GSM, MMModemSimtechGsmClass))
+
+typedef struct {
+ MMGenericGsm parent;
+} MMModemSimtechGsm;
+
+typedef struct {
+ MMGenericGsmClass parent;
+} MMModemSimtechGsmClass;
+
+GType mm_modem_simtech_gsm_get_type (void);
+
+MMModem *mm_modem_simtech_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin);
+
+#endif /* MM_MODEM_SIMTECH_H */
diff --git a/plugins/mm-modem-zte.c b/plugins/mm-modem-zte.c
index 92c23ae..ba8a1db 100644
--- a/plugins/mm-modem-zte.c
+++ b/plugins/mm-modem-zte.c
@@ -11,9 +11,10 @@
* 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 <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -22,6 +23,7 @@
#include "mm-serial-port.h"
#include "mm-errors.h"
#include "mm-callback-info.h"
+#include "mm-modem-helpers.h"
static void modem_init (MMModem *modem_class);
@@ -32,6 +34,8 @@ G_DEFINE_TYPE_EXTENDED (MMModemZte, mm_modem_zte, MM_TYPE_GENERIC_GSM, 0,
typedef struct {
gboolean init_retried;
+ guint32 cpms_tries;
+ guint cpms_timeout;
} MMModemZtePrivate;
MMModem *
@@ -51,35 +55,278 @@ mm_modem_zte_new (const char *device,
}
/*****************************************************************************/
-/* Modem class override functions */
+
+static void
+zte_access_tech_changed (MMAtSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data)
+{
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ char *str;
+
+ str = g_match_info_fetch (info, 1);
+ if (str)
+ act = mm_gsm_string_to_access_tech (str);
+ g_free (str);
+
+ mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (user_data), act);
+}
+
/*****************************************************************************/
static void
-init_modem_done (MMSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
+get_allowed_mode_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ GRegex *r = NULL;
+ GMatchInfo *match_info;
+
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (info->error)
+ goto done;
+
+ r = g_regex_new ("+ZSNT:\\s*(\\d),(\\d),(\\d)", G_REGEX_UNGREEDY, 0, NULL);
+ if (!r) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Failed to parse the allowed mode response");
+ goto done;
+ }
- mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
+ if (g_regex_match_full (r, response->str, response->len, 0, 0, &match_info, &info->error)) {
+ MMModemGsmAllowedMode mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+ char *str;
+ int cm_mode = -1, pref_acq = -1;
+
+ str = g_match_info_fetch (match_info, 1);
+ cm_mode = atoi (str);
+ g_free (str);
+
+ str = g_match_info_fetch (match_info, 3);
+ pref_acq = atoi (str);
+ g_free (str);
+
+ g_match_info_free (match_info);
+
+ if (cm_mode < 0 || cm_mode > 2 || pref_acq < 0 || pref_acq > 2) {
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Failed to parse the allowed mode response: '%s'",
+ response->str);
+ goto done;
+ }
+
+ if (cm_mode == 0) { /* Both 2G and 3G allowed */
+ if (pref_acq == 0)
+ mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+ else if (pref_acq == 1)
+ mode = MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED;
+ else if (pref_acq == 2)
+ mode = MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED;
+ } else if (cm_mode == 1) /* GSM only */
+ mode = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY;
+ else if (cm_mode == 2) /* WCDMA only */
+ mode = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY;
+
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mode), NULL);
+ }
+
+done:
+ if (r)
+ g_regex_unref (r);
+ 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, "AT+ZSNT?", 3, get_allowed_mode_done, info);
}
static void
-pin_check_done (MMModem *modem, GError *error, gpointer user_data)
+set_allowed_mode_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMSerialPort *primary;
- if (error) {
- mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info);
+ 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;
+ MMAtSerialPort *port;
+ char *command;
+ int cm_mode = 0, pref_acq = 0;
+
+ 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;
}
- /* Finish the initialization */
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
- mm_serial_port_queue_command (primary, "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1;", 10, init_modem_done, info);
+ switch (mode) {
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY:
+ cm_mode = 1;
+ pref_acq = 0;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY:
+ cm_mode = 2;
+ pref_acq = 0;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED:
+ cm_mode = 0;
+ pref_acq = 1;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED:
+ cm_mode = 0;
+ pref_acq = 2;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_ANY:
+ default:
+ break;
+ }
+
+ command = g_strdup_printf ("AT+ZSNT=%d,0,%d", cm_mode, pref_acq);
+ mm_at_serial_port_queue_command (port, command, 3, set_allowed_mode_done, info);
+ g_free (command);
+}
+
+static void
+get_act_request_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ const char *p;
+
+ if (error)
+ info->error = g_error_copy (error);
+ else {
+ /* Sample response from an MF626:
+ * +ZPAS: "GPRS/EDGE","CS_ONLY"
+ */
+ p = mm_strip_tag (response->str, "+ZPAS:");
+ act = mm_gsm_string_to_access_tech (p);
+ }
+
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (act), NULL);
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_access_technology (MMGenericGsm *modem,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMAtSerialPort *port;
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (modem, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (port, "+ZPAS?", 3, get_act_request_done, info);
+}
+
+/*****************************************************************************/
+/* Modem class override functions */
+/*****************************************************************************/
+
+static void cpms_try_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data);
+
+static gboolean
+cpms_timeout_cb (gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ MMModem *modem = info->modem;
+ MMAtSerialPort *primary;
+
+ if (modem) {
+ MM_MODEM_ZTE_GET_PRIVATE (modem)->cpms_timeout = 0;
+ primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+ mm_at_serial_port_queue_command (primary, "+CPMS?", 10, cpms_try_done, info);
+ }
+ return FALSE;
+}
+
+static void
+cpms_try_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (info->modem);
+
+ if (error && g_error_matches (error, MM_MOBILE_ERROR, MM_MOBILE_ERROR_SIM_BUSY)) {
+ if (priv->cpms_tries++ < 4) {
+ if (priv->cpms_timeout)
+ g_source_remove (priv->cpms_timeout);
+
+ /* Have to try a few times; sometimes the SIM is busy */
+ priv->cpms_timeout = g_timeout_add_seconds (2, cpms_timeout_cb, info);
+ return;
+ } else {
+ /* oh well, proceed... */
+ error = NULL;
+ }
+ }
+
+ mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
+}
+
+static void
+init_modem_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ /* 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
+ * accept the +CPMS? during the probe and we have to do it here.
+ */
+ mm_at_serial_port_queue_command (port, "+CPMS?", 10, cpms_try_done, info);
}
static void enable_flash_done (MMSerialPort *port,
@@ -87,7 +334,7 @@ static void enable_flash_done (MMSerialPort *port,
gpointer user_data);
static void
-pre_init_done (MMSerialPort *port,
+pre_init_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -98,15 +345,14 @@ pre_init_done (MMSerialPort *port,
if (error) {
/* Retry the init string one more time; the modem sometimes throws it away */
if ( !priv->init_retried
- && g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_RESPONSE_TIMEOUT)) {
+ && g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) {
priv->init_retried = TRUE;
- enable_flash_done (port, NULL, user_data);
+ enable_flash_done (MM_SERIAL_PORT (port), NULL, user_data);
} else
mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
} else {
- /* Now check the PIN explicitly, zte doesn't seem to report
- that it needs it otherwise */
- mm_generic_gsm_check_pin (MM_GENERIC_GSM (info->modem), pin_check_done, info);
+ /* Finish the initialization */
+ mm_at_serial_port_queue_command (port, "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1;", 10, init_modem_done, info);
}
}
@@ -118,7 +364,7 @@ enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
if (error)
mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
else
- mm_serial_port_queue_command (port, "E0 V1", 3, pre_init_done, user_data);
+ mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "E0 V1", 3, pre_init_done, user_data);
}
static void
@@ -126,15 +372,15 @@ do_enable (MMGenericGsm *modem, MMModemFn callback, gpointer user_data)
{
MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (modem);
MMCallbackInfo *info;
- MMSerialPort *primary;
+ MMAtSerialPort *primary;
priv->init_retried = FALSE;
- primary = mm_generic_gsm_get_port (modem, MM_PORT_TYPE_PRIMARY);
+ primary = mm_generic_gsm_get_at_port (modem, MM_PORT_TYPE_PRIMARY);
g_assert (primary);
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
- mm_serial_port_flash (primary, 100, enable_flash_done, info);
+ mm_serial_port_flash (MM_SERIAL_PORT (primary), 100, FALSE, enable_flash_done, info);
}
static void
@@ -165,42 +411,41 @@ grab_port (MMModem *modem,
MMPort *port = NULL;
if (suggested_type == MM_PORT_TYPE_UNKNOWN) {
- if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY))
+ if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY))
ptype = MM_PORT_TYPE_PRIMARY;
- else if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_SECONDARY))
+ 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_SERIAL_PORT (port)) {
+ if (port && MM_IS_AT_SERIAL_PORT (port)) {
GRegex *regex;
- mm_generic_gsm_set_unsolicited_registration (gsm, TRUE);
g_object_set (port, MM_PORT_CARRIER_DETECT, FALSE, NULL);
regex = g_regex_new ("\\r\\n\\+ZUSIMR:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
g_regex_unref (regex);
/* Unsolicted operator display */
regex = g_regex_new ("\\r\\n\\+ZDONR: (.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
g_regex_unref (regex);
/* Current network and service domain */
- regex = g_regex_new ("\\r\\n\\+ZPASR: (.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ regex = g_regex_new ("\\r\\n\\+ZPASR:\\s*(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, zte_access_tech_changed, modem, NULL);
g_regex_unref (regex);
/* SIM request to Build Main Menu */
regex = g_regex_new ("\\r\\n\\+ZPSTM: (.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
g_regex_unref (regex);
/* SIM request to Rebuild Main Menu */
regex = g_regex_new ("\\r\\n\\+ZEND\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
g_regex_unref (regex);
}
@@ -222,6 +467,16 @@ mm_modem_zte_init (MMModemZte *self)
}
static void
+dispose (GObject *object)
+{
+ MMModemZte *self = MM_MODEM_ZTE (object);
+ MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (self);
+
+ if (priv->cpms_timeout)
+ g_source_remove (priv->cpms_timeout);
+}
+
+static void
mm_modem_zte_class_init (MMModemZteClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -230,6 +485,10 @@ mm_modem_zte_class_init (MMModemZteClass *klass)
mm_modem_zte_parent_class = g_type_class_peek_parent (klass);
g_type_class_add_private (object_class, sizeof (MMModemZtePrivate));
+ object_class->dispose = dispose;
gsm_class->do_enable = do_enable;
+ 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-plugin-anydata.c b/plugins/mm-plugin-anydata.c
index e451714..94f4f10 100644
--- a/plugins/mm-plugin-anydata.c
+++ b/plugins/mm-plugin-anydata.c
@@ -42,9 +42,11 @@ mm_plugin_create (void)
static guint32
get_level_for_capabilities (guint32 capabilities)
{
- /* Only CDMA for now */
+ /* Only CDMA and QCDM for now */
if (capabilities & CAP_CDMA)
return 10;
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_QCDM)
+ return 10;
return 0;
}
@@ -104,7 +106,7 @@ grab_port (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
GError **error)
{
- GUdevDevice *port = NULL, *physdev = NULL;
+ GUdevDevice *port = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
@@ -118,14 +120,6 @@ grab_port (MMPluginBase *base,
return NULL;
}
- physdev = mm_plugin_base_supports_task_get_physdev (task);
- g_assert (physdev);
- sysfs_path = g_udev_device_get_sysfs_path (physdev);
- if (!sysfs_path) {
- g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- return NULL;
- }
-
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
@@ -135,6 +129,7 @@ grab_port (MMPluginBase *base,
return NULL;
}
+ sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
if (!existing) {
if (caps & CAP_CDMA) {
modem = mm_modem_anydata_cdma_new (sysfs_path,
@@ -150,12 +145,15 @@ grab_port (MMPluginBase *base,
return NULL;
}
}
- } else {
- if (caps & CAP_CDMA) {
- modem = existing;
- if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error))
- return NULL;
- }
+ } else if (get_level_for_capabilities (caps)) {
+ MMPortType ptype = MM_PORT_TYPE_UNKNOWN;
+
+ 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;
diff --git a/plugins/mm-plugin-generic.c b/plugins/mm-plugin-generic.c
index e5e2ade..cdf2c66 100644
--- a/plugins/mm-plugin-generic.c
+++ b/plugins/mm-plugin-generic.c
@@ -59,6 +59,8 @@ get_level_for_capabilities (guint32 capabilities)
return 5;
if (capabilities & CAP_CDMA)
return 5;
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_QCDM)
+ return 5;
return 0;
}
@@ -106,7 +108,7 @@ grab_port (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
GError **error)
{
- GUdevDevice *port = NULL, *physdev = NULL;
+ GUdevDevice *port = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path, *driver;
guint32 caps;
@@ -131,15 +133,8 @@ grab_port (MMPluginBase *base,
}
}
- physdev = mm_plugin_base_supports_task_get_physdev (task);
- g_assert (physdev);
- sysfs_path = g_udev_device_get_sysfs_path (physdev);
- if (!sysfs_path) {
- g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- 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,
@@ -159,12 +154,15 @@ grab_port (MMPluginBase *base,
return NULL;
}
}
- } else {
- if (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
- modem = existing;
- if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error))
- return NULL;
- }
+ } else if (get_level_for_capabilities (caps)) {
+ MMPortType ptype = MM_PORT_TYPE_UNKNOWN;
+
+ 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;
diff --git a/plugins/mm-plugin-gobi.c b/plugins/mm-plugin-gobi.c
index 77da965..fbe3878 100644
--- a/plugins/mm-plugin-gobi.c
+++ b/plugins/mm-plugin-gobi.c
@@ -102,7 +102,7 @@ grab_port (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
GError **error)
{
- GUdevDevice *port = NULL, *physdev = NULL;
+ GUdevDevice *port = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *sysfs_path;
guint32 caps;
@@ -110,18 +110,11 @@ grab_port (MMPluginBase *base,
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
- physdev = mm_plugin_base_supports_task_get_physdev (task);
- g_assert (physdev);
- sysfs_path = g_udev_device_get_sysfs_path (physdev);
- if (!sysfs_path) {
- g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- return NULL;
- }
-
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
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,
@@ -141,12 +134,10 @@ grab_port (MMPluginBase *base,
return NULL;
}
}
- } else {
- if (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
- modem = existing;
- if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error))
- 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;
diff --git a/plugins/mm-plugin-hso.c b/plugins/mm-plugin-hso.c
index 8493c9c..dc0a8fc 100644
--- a/plugins/mm-plugin-hso.c
+++ b/plugins/mm-plugin-hso.c
@@ -100,7 +100,7 @@ grab_port (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
GError **error)
{
- GUdevDevice *port = NULL, *physdev = NULL;
+ GUdevDevice *port = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *sysfs_path;
char *devfile;
@@ -131,18 +131,11 @@ grab_port (MMPluginBase *base,
}
}
- physdev = mm_plugin_base_supports_task_get_physdev (task);
- g_assert (physdev);
- sysfs_path = g_udev_device_get_sysfs_path (physdev);
- if (!sysfs_path) {
- g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- goto out;
- }
-
caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
if (!(caps & MM_PLUGIN_BASE_PORT_CAP_GSM) && strcmp (subsys, "net"))
goto out;
+ sysfs_path = mm_plugin_base_supports_task_get_physdev_path (task);
if (!existing) {
modem = mm_modem_hso_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
diff --git a/plugins/mm-plugin-huawei.c b/plugins/mm-plugin-huawei.c
index ad799f0..2993689 100644
--- a/plugins/mm-plugin-huawei.c
+++ b/plugins/mm-plugin-huawei.c
@@ -26,6 +26,7 @@
#include "mm-modem-huawei-gsm.h"
#include "mm-modem-huawei-cdma.h"
#include "mm-serial-parsers.h"
+#include "mm-at-serial-port.h"
G_DEFINE_TYPE (MMPluginHuawei, mm_plugin_huawei, MM_TYPE_PLUGIN_BASE)
@@ -54,6 +55,8 @@ get_level_for_capabilities (guint32 capabilities)
return 10;
if (capabilities & CAP_CDMA)
return 10;
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_QCDM)
+ return 10;
return 0;
}
@@ -69,9 +72,14 @@ probe_result (MMPluginBase *base,
#define TAG_SUPPORTS_INFO "huawei-supports-info"
typedef struct {
- MMSerialPort *serial;
+ MMAtSerialPort *serial;
guint id;
- gboolean secondary;
+ MMPortType ptype;
+ /* Whether or not there's already a detected modem that "owns" this port,
+ * in which case we'll claim it, but if no capabilities are detected it'll
+ * just be ignored.
+ */
+ gboolean parent_modem;
} HuaweiSupportsInfo;
static void
@@ -100,13 +108,13 @@ probe_secondary_supported (gpointer user_data)
info->serial = NULL;
/* Yay, supported, we got an unsolicited message */
- info->secondary = TRUE;
+ info->ptype = MM_PORT_TYPE_SECONDARY;
mm_plugin_base_supports_task_complete (task, 10);
return FALSE;
}
static void
-probe_secondary_handle_msg (MMSerialPort *port,
+probe_secondary_handle_msg (MMAtSerialPort *port,
GMatchInfo *match_info,
gpointer user_data)
{
@@ -123,24 +131,30 @@ probe_secondary_timeout (gpointer user_data)
{
MMPluginBaseSupportsTask *task = user_data;
HuaweiSupportsInfo *info;
+ guint level = 0;
info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO);
info->id = 0;
g_object_unref (info->serial);
info->serial = NULL;
- /* Not supported by this plugin */
- mm_plugin_base_supports_task_complete (task, 0);
+ /* Supported, but ignored if this port's parent device is already a modem */
+ if (info->parent_modem) {
+ info->ptype = MM_PORT_TYPE_IGNORED;
+ level = 10;
+ }
+
+ mm_plugin_base_supports_task_complete (task, level);
return FALSE;
}
static void
-add_regex (MMSerialPort *port, const char *match, gpointer user_data)
+add_regex (MMAtSerialPort *port, const char *match, gpointer user_data)
{
GRegex *regex;
regex = g_regex_new (match, G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (port, regex, probe_secondary_handle_msg, user_data, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (port, regex, probe_secondary_handle_msg, user_data, NULL);
g_regex_unref (regex);
}
@@ -207,14 +221,15 @@ supports_port (MMPluginBase *base,
/* Listen for Huawei-specific unsolicited messages */
info = g_malloc0 (sizeof (HuaweiSupportsInfo));
+ info->parent_modem = !!existing;
- info->serial = mm_serial_port_new (name, MM_PORT_TYPE_PRIMARY);
+ info->serial = mm_at_serial_port_new (name, MM_PORT_TYPE_PRIMARY);
g_object_set (G_OBJECT (info->serial), MM_PORT_CARRIER_DETECT, FALSE, NULL);
- mm_serial_port_set_response_parser (info->serial,
- mm_serial_parser_v1_parse,
- mm_serial_parser_v1_new (),
- mm_serial_parser_v1_destroy);
+ mm_at_serial_port_set_response_parser (info->serial,
+ mm_serial_parser_v1_parse,
+ mm_serial_parser_v1_new (),
+ mm_serial_parser_v1_destroy);
add_regex (info->serial, "\\r\\n\\^RSSI:(\\d+)\\r\\n", task);
add_regex (info->serial, "\\r\\n\\^MODE:(\\d),(\\d)\\r\\n", task);
@@ -222,12 +237,12 @@ supports_port (MMPluginBase *base,
add_regex (info->serial, "\\r\\n\\^BOOT:.+\\r\\n", task);
add_regex (info->serial, "\\r\\r\\^BOOT:.+\\r\\r", task);
- info->id = g_timeout_add (5000, probe_secondary_timeout, task);
+ 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 (info->serial, &error)) {
+ 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,
@@ -249,7 +264,7 @@ grab_port (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
GError **error)
{
- GUdevDevice *port = NULL, *physdev = NULL;
+ GUdevDevice *port = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
@@ -264,14 +279,6 @@ grab_port (MMPluginBase *base,
return NULL;
}
- physdev = mm_plugin_base_supports_task_get_physdev (task);
- g_assert (physdev);
- sysfs_path = g_udev_device_get_sysfs_path (physdev);
- if (!sysfs_path) {
- g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- return NULL;
- }
-
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
@@ -281,18 +288,12 @@ grab_port (MMPluginBase *base,
}
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) {
- if (product == 0x1001) {
- /* This modem is handled by generic GSM driver */
- modem = mm_generic_gsm_new (sysfs_path,
- mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
- } else {
- modem = mm_modem_huawei_gsm_new (sysfs_path,
- mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)));
- }
+ modem = mm_modem_huawei_gsm_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
} else if (caps & CAP_CDMA) {
modem = mm_modem_huawei_cdma_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
@@ -312,8 +313,10 @@ grab_port (MMPluginBase *base,
MMPortType ptype = MM_PORT_TYPE_UNKNOWN;
info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO);
- if (info && info->secondary && (product != 0x1001))
- ptype = MM_PORT_TYPE_SECONDARY;
+ if (info)
+ ptype = info->ptype;
+ else 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))
diff --git a/plugins/mm-plugin-longcheer.c b/plugins/mm-plugin-longcheer.c
index 5c19b13..dbbe186 100644
--- a/plugins/mm-plugin-longcheer.c
+++ b/plugins/mm-plugin-longcheer.c
@@ -11,12 +11,13 @@
* 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>
#include <gmodule.h>
#include "mm-plugin-longcheer.h"
+#include "mm-modem-longcheer-gsm.h"
#include "mm-generic-gsm.h"
#include "mm-generic-cdma.h"
@@ -47,6 +48,8 @@ get_level_for_capabilities (guint32 capabilities)
return 10;
if (capabilities & CAP_CDMA)
return 10;
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_QCDM)
+ return 10;
return 0;
}
@@ -80,7 +83,8 @@ supports_port (MMPluginBase *base,
if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, NULL))
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
- if (vendor != 0x1c9e)
+ /* Longcheer and TAMobile */
+ if (vendor != 0x1c9e && vendor != 0x1bbb)
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
@@ -105,7 +109,7 @@ grab_port (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
GError **error)
{
- GUdevDevice *port = NULL, *physdev = NULL;
+ GUdevDevice *port = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *sysfs_path;
guint32 caps;
@@ -131,23 +135,16 @@ grab_port (MMPluginBase *base,
&& g_udev_device_get_property_as_boolean (port, "ID_MM_LONGCHEER_TAGGED"))
ptype = MM_PORT_TYPE_IGNORED;
- physdev = mm_plugin_base_supports_task_get_physdev (task);
- g_assert (physdev);
- sysfs_path = g_udev_device_get_sysfs_path (physdev);
- if (!sysfs_path) {
- g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- return NULL;
- }
-
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
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)));
+ modem = mm_modem_longcheer_gsm_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
} else if (caps & CAP_CDMA) {
modem = mm_generic_cdma_new (sysfs_path,
mm_plugin_base_supports_task_get_driver (task),
@@ -162,12 +159,13 @@ grab_port (MMPluginBase *base,
return NULL;
}
}
- } else {
- if (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
- modem = existing;
- if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error))
- 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;
diff --git a/plugins/mm-plugin-mbm.c b/plugins/mm-plugin-mbm.c
index a380f98..5554d84 100644
--- a/plugins/mm-plugin-mbm.c
+++ b/plugins/mm-plugin-mbm.c
@@ -14,10 +14,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
*/
#include <string.h>
@@ -66,9 +62,12 @@ supports_port (MMPluginBase *base,
MMModem *existing,
MMPluginBaseSupportsTask *task)
{
+ GUdevClient *client;
+ const char *sys[] = { "tty", "net", NULL };
GUdevDevice *port, *physdev;
guint32 cached = 0, level;
- const char *driver, *subsys;
+ const char *driver, *subsys, *physdev_path;
+ gboolean is_mbm;
/* Can't do anything with non-serial ports */
port = mm_plugin_base_supports_task_get_port (task);
@@ -83,9 +82,23 @@ supports_port (MMPluginBase *base,
if (!driver)
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
- physdev = mm_plugin_base_supports_task_get_physdev (task);
+ client = g_udev_client_new (sys);
+ if (!client) {
+ g_warning ("mbm: could not get udev client.");
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ }
+
+ /* Look up the port's physical device and see if this port is really an
+ * 'mbm' modem, since we have no other way of telling.
+ */
+ physdev_path = mm_plugin_base_supports_task_get_physdev_path (task);
+ physdev = g_udev_client_query_by_sysfs_path (client, physdev_path);
g_assert (physdev);
- if (!g_udev_device_get_property_as_boolean (physdev, "ID_MM_ERICSSON_MBM"))
+
+ is_mbm = g_udev_device_get_property_as_boolean (physdev, "ID_MM_ERICSSON_MBM");
+ g_object_unref (client);
+
+ if (!is_mbm)
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
if (!strcmp (subsys, "net")) {
@@ -115,7 +128,7 @@ grab_port (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
GError **error)
{
- GUdevDevice *port = NULL, *physdev = NULL;
+ GUdevDevice *port = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *sysfs_path;
guint32 caps;
@@ -123,14 +136,6 @@ grab_port (MMPluginBase *base,
port = mm_plugin_base_supports_task_get_port (task);
g_assert (port);
- physdev = mm_plugin_base_supports_task_get_physdev (task);
- g_assert (physdev);
- sysfs_path = g_udev_device_get_sysfs_path (physdev);
- if (!sysfs_path) {
- g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- return NULL;
- }
-
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
@@ -138,6 +143,7 @@ grab_port (MMPluginBase *base,
if (!(caps & MM_PLUGIN_BASE_PORT_CAP_GSM) && strcmp (subsys, "net"))
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),
diff --git a/plugins/mm-plugin-mbm.h b/plugins/mm-plugin-mbm.h
index c0e73b5..c478f11 100644
--- a/plugins/mm-plugin-mbm.h
+++ b/plugins/mm-plugin-mbm.h
@@ -14,10 +14,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
*/
#ifndef MM_PLUGIN_MBM_H
diff --git a/plugins/mm-plugin-moto-c.c b/plugins/mm-plugin-moto-c.c
index 5b32a1e..d798af4 100644
--- a/plugins/mm-plugin-moto-c.c
+++ b/plugins/mm-plugin-moto-c.c
@@ -37,18 +37,21 @@ mm_plugin_create (void)
/*****************************************************************************/
+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)
{
- guint32 level = 0;
-
- if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
- level = 10;
-
- mm_plugin_base_supports_task_complete (task, level);
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
}
static MMPluginSupportsResult
@@ -58,7 +61,7 @@ supports_port (MMPluginBase *base,
{
GUdevDevice *port;
const char *tmp;
- guint32 cached = 0;
+ guint32 cached = 0, level;
/* Can't do anything with non-serial ports */
port = mm_plugin_base_supports_task_get_port (task);
@@ -78,7 +81,8 @@ supports_port (MMPluginBase *base,
return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
- if (cached & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
mm_plugin_base_supports_task_complete (task, 10);
return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
}
@@ -98,7 +102,7 @@ grab_port (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
GError **error)
{
- GUdevDevice *port = NULL, *physdev = NULL;
+ GUdevDevice *port = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path;
@@ -111,17 +115,10 @@ grab_port (MMPluginBase *base,
return NULL;
}
- physdev = mm_plugin_base_supports_task_get_physdev (task);
- g_assert (physdev);
- sysfs_path = g_udev_device_get_sysfs_path (physdev);
- if (!sysfs_path) {
- g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- return NULL;
- }
-
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
+ 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),
diff --git a/plugins/mm-plugin-nokia.c b/plugins/mm-plugin-nokia.c
index e088323..2d0d6af 100644
--- a/plugins/mm-plugin-nokia.c
+++ b/plugins/mm-plugin-nokia.c
@@ -105,7 +105,7 @@ grab_port (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
GError **error)
{
- GUdevDevice *port = NULL, *physdev = NULL;
+ GUdevDevice *port = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
@@ -119,18 +119,11 @@ grab_port (MMPluginBase *base,
return NULL;
}
- physdev = mm_plugin_base_supports_task_get_physdev (task);
- g_assert (physdev);
- sysfs_path = g_udev_device_get_sysfs_path (physdev);
- if (!sysfs_path) {
- g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- return NULL;
- }
-
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
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,
@@ -150,12 +143,10 @@ grab_port (MMPluginBase *base,
return NULL;
}
}
- } else {
- if (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
- modem = existing;
- if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error))
- 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;
diff --git a/plugins/mm-plugin-novatel.c b/plugins/mm-plugin-novatel.c
index 48ff7ec..a968836 100644
--- a/plugins/mm-plugin-novatel.c
+++ b/plugins/mm-plugin-novatel.c
@@ -18,7 +18,7 @@
#include <gmodule.h>
#include "mm-plugin-novatel.h"
#include "mm-modem-novatel-gsm.h"
-#include "mm-generic-cdma.h"
+#include "mm-modem-novatel-cdma.h"
G_DEFINE_TYPE (MMPluginNovatel, mm_plugin_novatel, MM_TYPE_PLUGIN_BASE)
@@ -47,6 +47,8 @@ get_level_for_capabilities (guint32 capabilities)
return 10;
if (capabilities & CAP_CDMA)
return 10;
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_QCDM)
+ return 10;
return 0;
}
@@ -109,7 +111,7 @@ grab_port (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
GError **error)
{
- GUdevDevice *port = NULL, *physdev = NULL;
+ GUdevDevice *port = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
@@ -123,29 +125,22 @@ grab_port (MMPluginBase *base,
return NULL;
}
- physdev = mm_plugin_base_supports_task_get_physdev (task);
- g_assert (physdev);
- sysfs_path = g_udev_device_get_sysfs_path (physdev);
- if (!sysfs_path) {
- g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- return NULL;
- }
-
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
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)));
} 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));
+ 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));
}
if (modem) {
@@ -154,12 +149,15 @@ grab_port (MMPluginBase *base,
return NULL;
}
}
- } else {
- if (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
- modem = existing;
- if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error))
- return NULL;
- }
+ } else if (get_level_for_capabilities (caps)) {
+ MMPortType ptype = MM_PORT_TYPE_UNKNOWN;
+
+ 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;
diff --git a/plugins/mm-plugin-option.c b/plugins/mm-plugin-option.c
index d4c402d..101f9bd 100644
--- a/plugins/mm-plugin-option.c
+++ b/plugins/mm-plugin-option.c
@@ -101,7 +101,7 @@ grab_port (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
GError **error)
{
- GUdevDevice *port = NULL, *physdev = NULL;
+ GUdevDevice *port = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
@@ -117,14 +117,6 @@ grab_port (MMPluginBase *base,
return NULL;
}
- physdev = mm_plugin_base_supports_task_get_physdev (task);
- g_assert (physdev);
- sysfs_path = g_udev_device_get_sysfs_path (physdev);
- if (!sysfs_path) {
- g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- return NULL;
- }
-
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
@@ -138,6 +130,7 @@ grab_port (MMPluginBase *base,
ptype = MM_PORT_TYPE_PRIMARY;
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,
@@ -151,12 +144,13 @@ grab_port (MMPluginBase *base,
return NULL;
}
}
- } else {
- if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
- modem = existing;
- if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error))
- 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;
diff --git a/plugins/mm-plugin-sierra.c b/plugins/mm-plugin-sierra.c
index 637f46d..8ace653 100644
--- a/plugins/mm-plugin-sierra.c
+++ b/plugins/mm-plugin-sierra.c
@@ -123,7 +123,7 @@ grab_port (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
GError **error)
{
- GUdevDevice *port = NULL, *physdev = NULL;
+ GUdevDevice *port = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *devfile, *sysfs_path;
guint32 caps;
@@ -138,14 +138,6 @@ grab_port (MMPluginBase *base,
return NULL;
}
- physdev = mm_plugin_base_supports_task_get_physdev (task);
- g_assert (physdev);
- sysfs_path = g_udev_device_get_sysfs_path (physdev);
- if (!sysfs_path) {
- g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- return NULL;
- }
-
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
@@ -154,6 +146,7 @@ grab_port (MMPluginBase *base,
ptype = MM_PORT_TYPE_SECONDARY;
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,
@@ -173,13 +166,10 @@ grab_port (MMPluginBase *base,
return NULL;
}
}
- } else {
- if ( (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA))
- || (ptype != MM_PORT_TYPE_UNKNOWN)) {
- modem = existing;
- if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error))
- return NULL;
- }
+ } else if (get_level_for_capabilities (caps) || (ptype != MM_PORT_TYPE_UNKNOWN)) {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error))
+ return NULL;
}
return modem;
diff --git a/plugins/mm-plugin-simtech.c b/plugins/mm-plugin-simtech.c
new file mode 100644
index 0000000..3c44873
--- /dev/null
+++ b/plugins/mm-plugin-simtech.c
@@ -0,0 +1,189 @@
+/* -*- 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-simtech.h"
+#include "mm-modem-simtech-gsm.h"
+#include "mm-generic-gsm.h"
+#include "mm-generic-cdma.h"
+
+G_DEFINE_TYPE (MMPluginSimtech, mm_plugin_simtech, 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_SIMTECH,
+ MM_PLUGIN_BASE_NAME, "SimTech",
+ NULL));
+}
+
+/*****************************************************************************/
+
+#define CAP_CDMA (MM_PLUGIN_BASE_PORT_CAP_IS707_A | \
+ MM_PLUGIN_BASE_PORT_CAP_IS707_P | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856 | \
+ MM_PLUGIN_BASE_PORT_CAP_IS856_A)
+
+static guint32
+get_level_for_capabilities (guint32 capabilities)
+{
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 10;
+ if (capabilities & CAP_CDMA)
+ return 10;
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_QCDM)
+ 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;
+ 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;
+
+ /* A-Link (for now) */
+ if (vendor != 0x1e0e)
+ 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;
+
+ 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_SIMTECH_PORT_TYPE_MODEM"))
+ ptype = MM_PORT_TYPE_PRIMARY;
+ else if (g_udev_device_get_property_as_boolean (port, "ID_MM_SIMTECH_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_SIMTECH_TAGGED"))
+ ptype = MM_PORT_TYPE_IGNORED;
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ 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)));
+ } 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));
+ }
+
+ 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_simtech_init (MMPluginSimtech *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_simtech_class_init (MMPluginSimtechClass *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-simtech.h b/plugins/mm-plugin-simtech.h
new file mode 100644
index 0000000..e316056
--- /dev/null
+++ b/plugins/mm-plugin-simtech.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_SIMTECH_H
+#define MM_PLUGIN_SIMTECH_H
+
+#include "mm-plugin-base.h"
+
+#define MM_TYPE_PLUGIN_SIMTECH (mm_plugin_simtech_get_type ())
+#define MM_PLUGIN_SIMTECH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_SIMTECH, MMPluginSimtech))
+#define MM_PLUGIN_SIMTECH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_SIMTECH, MMPluginSimtechClass))
+#define MM_IS_PLUGIN_SIMTECH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_SIMTECH))
+#define MM_IS_PLUGIN_SIMTECH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_SIMTECH))
+#define MM_PLUGIN_SIMTECH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_SIMTECH, MMPluginSimtechClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginSimtech;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginSimtechClass;
+
+GType mm_plugin_simtech_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_SIMTECH_H */
diff --git a/plugins/mm-plugin-zte.c b/plugins/mm-plugin-zte.c
index 101fb46..e943bbf 100644
--- a/plugins/mm-plugin-zte.c
+++ b/plugins/mm-plugin-zte.c
@@ -47,6 +47,8 @@ get_level_for_capabilities (guint32 capabilities)
return 10;
if (capabilities & CAP_CDMA)
return 10;
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_QCDM)
+ return 10;
return 0;
}
@@ -100,7 +102,7 @@ supports_port (MMPluginBase *base,
* 1235f71b20c92cded4abd976ccc5010649aae1a0 and
* f38ad328acfdc6ce29dd1380602c546b064161ae for more details.
*/
- mm_plugin_base_supports_task_set_custom_init_command (task, "ATE0+CPMS?", 3, 4, TRUE);
+ mm_plugin_base_supports_task_set_custom_init_command (task, "ATE0+CPMS?", 3, 4, FALSE);
if (mm_plugin_base_probe_port (base, task, NULL))
return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
@@ -114,7 +116,7 @@ grab_port (MMPluginBase *base,
MMPluginBaseSupportsTask *task,
GError **error)
{
- GUdevDevice *port = NULL, *physdev = NULL;
+ GUdevDevice *port = NULL;
MMModem *modem = NULL;
const char *name, *subsys, *sysfs_path;
guint32 caps;
@@ -129,18 +131,11 @@ grab_port (MMPluginBase *base,
else if (g_udev_device_get_property_as_boolean (port, "ID_MM_ZTE_PORT_TYPE_AUX"))
ptype = MM_PORT_TYPE_SECONDARY;
- physdev = mm_plugin_base_supports_task_get_physdev (task);
- g_assert (physdev);
- sysfs_path = g_udev_device_get_sysfs_path (physdev);
- if (!sysfs_path) {
- g_set_error (error, 0, 0, "Could not get port's physical device sysfs path.");
- return NULL;
- }
-
subsys = g_udev_device_get_subsystem (port);
name = g_udev_device_get_name (port);
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,
@@ -160,12 +155,13 @@ grab_port (MMPluginBase *base,
return NULL;
}
}
- } else {
- if (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
- modem = existing;
- if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error))
- 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;