aboutsummaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorGuido Günther <agx@sigxcpu.org>2014-02-05 08:38:15 +0100
committerGuido Günther <agx@sigxcpu.org>2014-02-05 08:38:15 +0100
commit87bd9deec22af69bb27226254803ac5c63b18d78 (patch)
treec34d42bf75c20b3fd740e4cd59e45aa6901a9fed /plugins
Imported Upstream version 0.3upstream/0.3
Diffstat (limited to 'plugins')
-rw-r--r--plugins/77-mm-ericsson-mbm.rules41
-rw-r--r--plugins/77-mm-longcheer-port-types.rules45
-rw-r--r--plugins/77-mm-zte-port-types.rules115
-rw-r--r--plugins/Makefile.am268
-rw-r--r--plugins/mm-modem-anydata-cdma.c384
-rw-r--r--plugins/mm-modem-anydata-cdma.h45
-rw-r--r--plugins/mm-modem-gobi-gsm.c109
-rw-r--r--plugins/mm-modem-gobi-gsm.h43
-rw-r--r--plugins/mm-modem-hso.c743
-rw-r--r--plugins/mm-modem-hso.h49
-rw-r--r--plugins/mm-modem-huawei-cdma.c316
-rw-r--r--plugins/mm-modem-huawei-cdma.h45
-rw-r--r--plugins/mm-modem-huawei-gsm.c621
-rw-r--r--plugins/mm-modem-huawei-gsm.h43
-rw-r--r--plugins/mm-modem-mbm.c830
-rw-r--r--plugins/mm-modem-mbm.h52
-rw-r--r--plugins/mm-modem-moto-c-gsm.c129
-rw-r--r--plugins/mm-modem-moto-c-gsm.h43
-rw-r--r--plugins/mm-modem-nokia.c142
-rw-r--r--plugins/mm-modem-nokia.h43
-rw-r--r--plugins/mm-modem-novatel-gsm.c184
-rw-r--r--plugins/mm-modem-novatel-gsm.h43
-rw-r--r--plugins/mm-modem-option.c244
-rw-r--r--plugins/mm-modem-option.h43
-rw-r--r--plugins/mm-modem-sierra-cdma.c383
-rw-r--r--plugins/mm-modem-sierra-cdma.h45
-rw-r--r--plugins/mm-modem-sierra-gsm.c145
-rw-r--r--plugins/mm-modem-sierra-gsm.h43
-rw-r--r--plugins/mm-modem-zte.c235
-rw-r--r--plugins/mm-modem-zte.h43
-rw-r--r--plugins/mm-plugin-anydata.c179
-rw-r--r--plugins/mm-plugin-anydata.h41
-rw-r--r--plugins/mm-plugin-generic.c189
-rw-r--r--plugins/mm-plugin-generic.h41
-rw-r--r--plugins/mm-plugin-gobi.c171
-rw-r--r--plugins/mm-plugin-gobi.h44
-rw-r--r--plugins/mm-plugin-hso.c182
-rw-r--r--plugins/mm-plugin-hso.h43
-rw-r--r--plugins/mm-plugin-huawei.c341
-rw-r--r--plugins/mm-plugin-huawei.h42
-rw-r--r--plugins/mm-plugin-longcheer.c191
-rw-r--r--plugins/mm-plugin-longcheer.h41
-rw-r--r--plugins/mm-plugin-mbm.c175
-rw-r--r--plugins/mm-plugin-mbm.h48
-rw-r--r--plugins/mm-plugin-moto-c.c160
-rw-r--r--plugins/mm-plugin-moto-c.h43
-rw-r--r--plugins/mm-plugin-nokia.c179
-rw-r--r--plugins/mm-plugin-nokia.h41
-rw-r--r--plugins/mm-plugin-novatel.c183
-rw-r--r--plugins/mm-plugin-novatel.h42
-rw-r--r--plugins/mm-plugin-option.c180
-rw-r--r--plugins/mm-plugin-option.h42
-rw-r--r--plugins/mm-plugin-sierra.c204
-rw-r--r--plugins/mm-plugin-sierra.h42
-rw-r--r--plugins/mm-plugin-zte.c189
-rw-r--r--plugins/mm-plugin-zte.h41
56 files changed, 8588 insertions, 0 deletions
diff --git a/plugins/77-mm-ericsson-mbm.rules b/plugins/77-mm-ericsson-mbm.rules
new file mode 100644
index 0000000..71dc6b8
--- /dev/null
+++ b/plugins/77-mm-ericsson-mbm.rules
@@ -0,0 +1,41 @@
+# do not edit this file, it will be overwritten on update
+
+ACTION!="add|change", GOTO="mm_mbm_end"
+SUBSYSTEM!="usb", GOTO="mm_mbm_end"
+ENV{DEVTYPE}!="usb_device", GOTO="mm_mbm_end"
+
+# Ericsson F3507g
+ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1900", ENV{ID_MM_ERICSSON_MBM}="1"
+ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1902", ENV{ID_MM_ERICSSON_MBM}="1"
+
+# Ericsson F3607gw
+ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1904", ENV{ID_MM_ERICSSON_MBM}="1"
+ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1905", ENV{ID_MM_ERICSSON_MBM}="1"
+ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1906", ENV{ID_MM_ERICSSON_MBM}="1"
+
+# Ericsson F3307
+ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="190a", ENV{ID_MM_ERICSSON_MBM}="1"
+ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1909", ENV{ID_MM_ERICSSON_MBM}="1"
+
+# Ericsson C3607w
+ATTRS{idVendor}=="0bdb", ATTRS{idProduct}=="1049", ENV{ID_MM_ERICSSON_MBM}="1"
+
+# Sony-Ericsson MD300
+ATTRS{idVendor}=="0fce", ATTRS{idProduct}=="d0cf", ENV{ID_MM_ERICSSON_MBM}="1"
+
+# Dell 5530 HSDPA
+ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8147", ENV{ID_MM_ERICSSON_MBM}="1"
+
+# Dell F3607gw
+ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8183", ENV{ID_MM_ERICSSON_MBM}="1"
+ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8184", ENV{ID_MM_ERICSSON_MBM}="1"
+
+# Toshiba
+ATTRS{idVendor}=="0930", ATTRS{idProduct}=="130b", ENV{ID_MM_ERICSSON_MBM}="1"
+
+# Toshiba F3607gw
+ATTRS{idVendor}=="0930", ATTRS{idProduct}=="130c", ENV{ID_MM_ERICSSON_MBM}="1"
+ATTRS{idVendor}=="0930", ATTRS{idProduct}=="1311", ENV{ID_MM_ERICSSON_MBM}="1"
+
+LABEL="mm_mbm_end"
+
diff --git a/plugins/77-mm-longcheer-port-types.rules b/plugins/77-mm-longcheer-port-types.rules
new file mode 100644
index 0000000..7317df7
--- /dev/null
+++ b/plugins/77-mm-longcheer-port-types.rules
@@ -0,0 +1,45 @@
+# do not edit this file, it will be overwritten on update
+
+# Longcheer makes modules that other companies rebrand, like:
+#
+# Alcatel One Touch X020
+# Alcatel One Touch X030
+# MobiData MBD-200HU
+# ST Mobile Connect HSUPA USB Modem
+
+
+ACTION!="add|change", GOTO="mm_longcheer_port_types_end"
+SUBSYSTEM!="tty", GOTO="mm_longcheer_port_types_end"
+
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="1c9e", GOTO="mm_longcheer_vendorcheck"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="1bbb", GOTO="mm_tamobile_vendorcheck"
+GOTO="mm_longcheer_port_types_end"
+
+LABEL="mm_longcheer_vendorcheck"
+SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
+
+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"
+
+# Alcatel One Touch X020
+ATTRS{idProduct}=="6061", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="6061", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="6061", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+GOTO="mm_longcheer_port_types_end"
+
+
+LABEL="mm_tamobile_vendorcheck"
+SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
+
+# Alcatel One Touch X060s
+ATTRS{idProduct}=="0000", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_LONGCHEER_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0000", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_LONGCHEER_PORT_TYPE_AUX}="1"
+ATTRS{idProduct}=="0000", ENV{ID_MM_LONGCHEER_TAGGED}="1"
+
+GOTO="mm_longcheer_port_types_end"
+
+
+LABEL="mm_longcheer_port_types_end"
+
diff --git a/plugins/77-mm-zte-port-types.rules b/plugins/77-mm-zte-port-types.rules
new file mode 100644
index 0000000..9d64aa9
--- /dev/null
+++ b/plugins/77-mm-zte-port-types.rules
@@ -0,0 +1,115 @@
+# do not edit this file, it will be overwritten on update
+
+ACTION!="add|change", GOTO="mm_zte_port_types_end"
+SUBSYSTEM!="tty", GOTO="mm_zte_port_types_end"
+
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="19d2", GOTO="mm_zte_port_types_vendorcheck"
+GOTO="mm_zte_port_types_end"
+
+LABEL="mm_zte_port_types_vendorcheck"
+SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
+
+ATTRS{idProduct}=="0001", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0001", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0002", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0002", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0003", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0003", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0004", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0004", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0005", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0005", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0006", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0006", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0007", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0007", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0008", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0008", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0009", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0009", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="000A", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="000A", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0012", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0012", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0015", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0015", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0016", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0016", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0017", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0017", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0018", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0018", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0019", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0019", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0021", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0021", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0024", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0024", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0025", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0025", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0030", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0030", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0031", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0031", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0033", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0033", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0037", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0037", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0042", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0042", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0043", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0043", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0048", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0048", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0049", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0049", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0052", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0052", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0055", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0055", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0063", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0063", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0064", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0064", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="0066", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="0066", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+ATTRS{idProduct}=="2002", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1"
+ATTRS{idProduct}=="2002", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1"
+
+LABEL="mm_zte_port_types_end"
+
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
new file mode 100644
index 0000000..a361358
--- /dev/null
+++ b/plugins/Makefile.am
@@ -0,0 +1,268 @@
+pkglib_LTLIBRARIES = \
+ libmm-plugin-generic.la \
+ libmm-plugin-moto-c.la \
+ libmm-plugin-gobi.la \
+ libmm-plugin-huawei.la \
+ libmm-plugin-hso.la \
+ libmm-plugin-option.la \
+ libmm-plugin-sierra.la \
+ libmm-plugin-novatel.la \
+ libmm-plugin-nokia.la \
+ libmm-plugin-zte.la \
+ libmm-plugin-mbm.la \
+ libmm-plugin-longcheer.la \
+ libmm-plugin-anydata.la
+
+# Generic
+
+libmm_plugin_generic_la_SOURCES = \
+ mm-plugin-generic.c \
+ mm-plugin-generic.h
+
+libmm_plugin_generic_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_generic_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
+
+# Motorola C-series phones
+
+libmm_plugin_moto_c_la_SOURCES = \
+ mm-plugin-moto-c.c \
+ mm-plugin-moto-c.h \
+ mm-modem-moto-c-gsm.c \
+ mm-modem-moto-c-gsm.h
+
+libmm_plugin_moto_c_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_moto_c_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
+
+# Qualcomm Gobi
+
+libmm_plugin_gobi_la_SOURCES = \
+ mm-plugin-gobi.c \
+ mm-plugin-gobi.h \
+ mm-modem-gobi-gsm.c \
+ mm-modem-gobi-gsm.h
+
+libmm_plugin_gobi_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_gobi_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
+
+# Huawei
+
+libmm_plugin_huawei_la_SOURCES = \
+ mm-plugin-huawei.c \
+ mm-plugin-huawei.h \
+ mm-modem-huawei-gsm.c \
+ mm-modem-huawei-gsm.h \
+ mm-modem-huawei-cdma.c \
+ mm-modem-huawei-cdma.h
+
+libmm_plugin_huawei_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_huawei_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
+
+# HSO
+
+libmm_plugin_hso_la_SOURCES = \
+ mm-plugin-hso.c \
+ mm-plugin-hso.h \
+ mm-modem-gsm-hso-glue.h \
+ mm-modem-hso.c \
+ mm-modem-hso.h
+
+mm-modem-gsm-hso-glue.h: $(top_srcdir)/introspection/mm-modem-gsm-hso.xml
+ dbus-binding-tool --prefix=mm_modem_gsm_hso --mode=glib-server --output=$@ $<
+
+libmm_plugin_hso_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_hso_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
+
+# MBM
+
+libmm_plugin_mbm_la_SOURCES = \
+ mm-plugin-mbm.c \
+ mm-plugin-mbm.h \
+ mm-modem-mbm.c \
+ mm-modem-mbm.h
+
+libmm_plugin_mbm_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_mbm_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
+
+# Option
+
+libmm_plugin_option_la_SOURCES = \
+ mm-plugin-option.c \
+ mm-plugin-option.h \
+ mm-modem-option.c \
+ mm-modem-option.h
+
+libmm_plugin_option_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_option_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
+
+# Sierra
+
+libmm_plugin_sierra_la_SOURCES = \
+ mm-plugin-sierra.c \
+ mm-plugin-sierra.h \
+ mm-modem-sierra-gsm.c \
+ mm-modem-sierra-gsm.h \
+ mm-modem-sierra-cdma.c \
+ mm-modem-sierra-cdma.h
+
+libmm_plugin_sierra_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_sierra_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
+
+# Novatel
+
+libmm_plugin_novatel_la_SOURCES = \
+ mm-plugin-novatel.c \
+ mm-plugin-novatel.h \
+ mm-modem-novatel-gsm.c \
+ mm-modem-novatel-gsm.h
+
+libmm_plugin_novatel_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_novatel_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
+
+# Nokia
+
+libmm_plugin_nokia_la_SOURCES = \
+ mm-plugin-nokia.c \
+ mm-plugin-nokia.h \
+ mm-modem-nokia.c \
+ mm-modem-nokia.h
+
+libmm_plugin_nokia_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_nokia_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
+
+# Zte
+
+libmm_plugin_zte_la_SOURCES = \
+ mm-plugin-zte.c \
+ mm-plugin-zte.h \
+ mm-modem-zte.c \
+ mm-modem-zte.h
+
+libmm_plugin_zte_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_zte_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
+
+# Longcheer (and rebranded dongles)
+
+libmm_plugin_longcheer_la_SOURCES = \
+ mm-plugin-longcheer.c \
+ mm-plugin-longcheer.h
+
+libmm_plugin_longcheer_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_longcheer_la_LDFLAGS = \
+ $(GUDEV_LDFLAGS) \
+ -module \
+ -avoid-version
+
+# AnyData CDMA
+
+libmm_plugin_anydata_la_SOURCES = \
+ mm-plugin-anydata.c \
+ mm-plugin-anydata.h \
+ mm-modem-anydata-cdma.c \
+ mm-modem-anydata-cdma.h
+
+libmm_plugin_anydata_la_CPPFLAGS = \
+ $(MM_CFLAGS) \
+ $(GUDEV_CFLAGS) \
+ -I$(top_srcdir)/src
+
+libmm_plugin_anydata_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
+
+BUILT_SOURCES = \
+ mm-modem-gsm-hso-glue.h
+
+CLEANFILES = $(BUILT_SOURCES)
+
+EXTRA_DIST = \
+ $(udevrules_DATA)
+
diff --git a/plugins/mm-modem-anydata-cdma.c b/plugins/mm-modem-anydata-cdma.c
new file mode 100644
index 0000000..f6528ec
--- /dev/null
+++ b/plugins/mm-modem-anydata-cdma.c
@@ -0,0 +1,384 @@
+/* -*- 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>
+
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+
+#include "mm-modem-anydata-cdma.h"
+#include "mm-errors.h"
+#include "mm-callback-info.h"
+#include "mm-serial-port.h"
+#include "mm-serial-parsers.h"
+
+static void modem_init (MMModem *modem_class);
+
+G_DEFINE_TYPE_EXTENDED (MMModemAnydataCdma, mm_modem_anydata_cdma, MM_TYPE_GENERIC_CDMA, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init))
+
+MMModem *
+mm_modem_anydata_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_ANYDATA_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, FALSE,
+ NULL));
+}
+
+/*****************************************************************************/
+
+static const char *
+strip_response (const char *resp, const char *cmd)
+{
+ const char *p = resp;
+
+ if (p) {
+ if (!strncmp (p, cmd, strlen (cmd)))
+ p += strlen (cmd);
+ while (*p == ' ')
+ p++;
+ }
+ return p;
+}
+
+static gboolean
+uint_from_match_item (GMatchInfo *match_info, guint32 num, guint32 *val)
+{
+ long int tmp;
+ char *str;
+ gboolean success = FALSE;
+
+ str = g_match_info_fetch (match_info, num);
+ g_return_val_if_fail (str != NULL, FALSE);
+
+ errno = 0;
+ tmp = strtol (str, NULL, 10);
+ if (errno == 0 && tmp >= 0 && tmp <= G_MAXUINT) {
+ *val = (guint32) tmp;
+ success = TRUE;
+ }
+ g_free (str);
+ return success;
+}
+
+static gboolean
+int_from_match_item (GMatchInfo *match_info, guint32 num, gint *val)
+{
+ long int tmp;
+ char *str;
+ gboolean success = FALSE;
+
+ str = g_match_info_fetch (match_info, num);
+ g_return_val_if_fail (str != NULL, FALSE);
+
+ errno = 0;
+ tmp = strtol (str, NULL, 10);
+ if (errno == 0 && tmp >= G_MININT && tmp <= G_MAXINT) {
+ *val = (gint) tmp;
+ success = TRUE;
+ }
+ g_free (str);
+ return success;
+}
+
+static void
+evdo_state_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemCdmaRegistrationState reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
+ const char *reply;
+ 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);
+ }
+
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ reply = strip_response (response->str, "*HSTATE:");
+
+ /* Format is "<at state>,<session state>,<channel>,<pn>,<EcIo>,<rssi>,..." */
+ r = g_regex_new ("\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*([^,\\)]*)\\s*,\\s*([^,\\)]*)\\s*,.*",
+ 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_regex_match (r, reply, 0, &match_info);
+ if (g_match_info_get_match_count (match_info) >= 6) {
+ guint32 val = 0;
+ gint dbm = 0;
+
+ /* dBm is between -106 (worst) and -20.7 (best) */
+ int_from_match_item (match_info, 6, &dbm);
+
+ /* Parse the EVDO radio state */
+ if (uint_from_match_item (match_info, 1, &val)) {
+ switch (val) {
+ case 3: /* IDLE */
+ /* If IDLE and the EVDO dBm is -105 or lower, assume no service.
+ * It may be that IDLE actually means NO SERVICE too; not sure.
+ */
+ if (dbm > -105)
+ reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
+ break;
+ case 4: /* ACCESS */
+ case 5: /* CONNECT */
+ reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
+ break;
+ default:
+ g_message ("ANYDATA: unknown *STATE (%d); assuming no service.", val);
+ /* fall through */
+ case 0: /* NO SERVICE */
+ case 1: /* ACQUISITION */
+ case 2: /* SYNC */
+ break;
+ }
+ }
+ }
+
+ mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, reg_state);
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+state_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemCdmaRegistrationState reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
+ const char *reply;
+ 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);
+ }
+
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ reply = strip_response (response->str, "*STATE:");
+
+ /* Format is "<channel>,<pn>,<sid>,<nid>,<state>,<rssi>,..." */
+ 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).");
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ g_regex_match (r, reply, 0, &match_info);
+ if (g_match_info_get_match_count (match_info) >= 6) {
+ guint32 val = 0;
+ gint dbm = 0;
+
+ /* dBm is between -106 (worst) and -20.7 (best) */
+ int_from_match_item (match_info, 6, &dbm);
+
+ /* Parse the 1x radio state */
+ if (uint_from_match_item (match_info, 5, &val)) {
+ switch (val) {
+ case 1: /* IDLE */
+ /* If IDLE and the 1X dBm is -105 or lower, assume no service.
+ * It may be that IDLE actually means NO SERVICE too; not sure.
+ */
+ if (dbm > -105)
+ reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
+ break;
+ case 2: /* ACCESS */
+ case 3: /* PAGING */
+ case 4: /* TRAFFIC */
+ reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
+ break;
+ default:
+ g_message ("ANYDATA: unknown *STATE (%d); assuming no service.", val);
+ /* fall through */
+ case 0: /* NO SERVICE */
+ break;
+ }
+ }
+ }
+
+ 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);
+}
+
+static void
+query_registration_state (MMGenericCdma *cdma,
+ 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);
+
+ 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;
+ }
+
+ mm_serial_port_queue_command (port, "*STATE?", 3, state_done, info);
+}
+
+/*****************************************************************************/
+
+static gboolean
+grab_port (MMModem *modem,
+ const char *subsys,
+ const char *name,
+ MMPortType suggested_type,
+ gpointer user_data,
+ GError **error)
+{
+ MMPort *port = NULL;
+ 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)) {
+ /* 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);
+ 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);
+ 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);
+ g_regex_unref (regex);
+
+ /* Abnomral state notifications
+ *
+ * FIXME: set 1X/EVDO registration state to UNKNOWN when these
+ * notifications are received?
+ */
+
+ /* 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);
+ 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);
+ 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);
+ g_regex_unref (regex);
+ }
+
+ return !!port;
+}
+
+/*****************************************************************************/
+
+static void
+modem_init (MMModem *modem_class)
+{
+ modem_class->grab_port = grab_port;
+}
+
+static void
+mm_modem_anydata_cdma_init (MMModemAnydataCdma *self)
+{
+}
+
+static void
+mm_modem_anydata_cdma_class_init (MMModemAnydataCdmaClass *klass)
+{
+ MMGenericCdmaClass *cdma_class = MM_GENERIC_CDMA_CLASS (klass);
+
+ mm_modem_anydata_cdma_parent_class = g_type_class_peek_parent (klass);
+
+ cdma_class->query_registration_state = query_registration_state;
+
+#if 0
+ /* FIXME: maybe use AT*SLEEP=0/1 to disable/enable slotted mode for powersave */
+ cdma_class->post_enable = post_enable;
+ cdma_class->post_enable = post_disable;
+#endif
+}
+
diff --git a/plugins/mm-modem-anydata-cdma.h b/plugins/mm-modem-anydata-cdma.h
new file mode 100644
index 0000000..d2695d5
--- /dev/null
+++ b/plugins/mm-modem-anydata-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_ANYDATA_CDMA_H
+#define MM_MODEM_ANYDATA_CDMA_H
+
+#include "mm-generic-cdma.h"
+
+#define MM_TYPE_MODEM_ANYDATA_CDMA (mm_modem_anydata_cdma_get_type ())
+#define MM_MODEM_ANYDATA_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_ANYDATA_CDMA, MMModemAnydataCdma))
+#define MM_MODEM_ANYDATA_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_ANYDATA_CDMA, MMModemAnydataCdmaClass))
+#define MM_IS_MODEM_ANYDATA_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_ANYDATA_CDMA))
+#define MM_IS_MODEM_ANYDATA_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_ANYDATA_CDMA))
+#define MM_MODEM_ANYDATA_CDMA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_ANYDATA_CDMA, MMModemAnydataCdmaClass))
+
+typedef struct {
+ MMGenericCdma parent;
+} MMModemAnydataCdma;
+
+typedef struct {
+ MMGenericCdmaClass parent;
+} MMModemAnydataCdmaClass;
+
+GType mm_modem_anydata_cdma_get_type (void);
+
+MMModem *mm_modem_anydata_cdma_new (const char *device,
+ const char *driver,
+ const char *plugin,
+ gboolean evdo_rev0,
+ gboolean evdo_revA);
+
+#endif /* MM_MODEM_ANYDATA_CDMA_H */
diff --git a/plugins/mm-modem-gobi-gsm.c b/plugins/mm-modem-gobi-gsm.c
new file mode 100644
index 0000000..7ea9f8f
--- /dev/null
+++ b/plugins/mm-modem-gobi-gsm.c
@@ -0,0 +1,109 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mm-modem-gobi-gsm.h"
+#include "mm-errors.h"
+#include "mm-callback-info.h"
+#include "mm-modem-gsm-card.h"
+
+static void modem_init (MMModem *modem_class);
+static void modem_gsm_card_init (MMModemGsmCard *gsm_card_class);
+
+G_DEFINE_TYPE_EXTENDED (MMModemGobiGsm, mm_modem_gobi_gsm, MM_TYPE_GENERIC_GSM, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_CARD, modem_gsm_card_init))
+
+
+MMModem *
+mm_modem_gobi_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_GOBI_GSM,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ NULL));
+}
+
+/*****************************************************************************/
+
+static void
+get_string_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ if (error && response && !strcmp (response->str, "ERROR")) {
+ info->error = g_error_new_literal (MM_MOBILE_ERROR,
+ MM_MOBILE_ERROR_SIM_NOT_INSERTED,
+ "Unable to read IMSI");
+ } else if (error)
+ info->error = g_error_copy (error);
+ else
+ mm_callback_info_set_result (info, g_strdup (response->str), g_free);
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_imsi (MMModemGsmCard *modem,
+ MMModemStringFn callback,
+ gpointer user_data)
+{
+ MMSerialPort *primary;
+ 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);
+}
+
+static void
+modem_gsm_card_init (MMModemGsmCard *class)
+{
+ class->get_imsi = get_imsi;
+}
+
+/*****************************************************************************/
+
+static void
+modem_init (MMModem *modem_class)
+{
+}
+
+static void
+mm_modem_gobi_gsm_init (MMModemGobiGsm *self)
+{
+}
+
+static void
+mm_modem_gobi_gsm_class_init (MMModemGobiGsmClass *klass)
+{
+}
+
diff --git a/plugins/mm-modem-gobi-gsm.h b/plugins/mm-modem-gobi-gsm.h
new file mode 100644
index 0000000..4bd262f
--- /dev/null
+++ b/plugins/mm-modem-gobi-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_GOBI_GSM_H
+#define MM_MODEM_GOBI_GSM_H
+
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_GOBI_GSM (mm_modem_gobi_gsm_get_type ())
+#define MM_MODEM_GOBI_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_GOBI_GSM, MMModemGobiGsm))
+#define MM_MODEM_GOBI_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_GOBI_GSM, MMModemGobiGsmClass))
+#define MM_IS_MODEM_GOBI_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_GOBI_GSM))
+#define MM_IS_MODEM_GOBI_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_GOBI_GSM))
+#define MM_MODEM_GOBI_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_GOBI_GSM, MMModemGobiGsmClass))
+
+typedef struct {
+ MMGenericGsm parent;
+} MMModemGobiGsm;
+
+typedef struct {
+ MMGenericGsmClass parent;
+} MMModemGobiGsmClass;
+
+GType mm_modem_gobi_gsm_get_type (void);
+
+MMModem *mm_modem_gobi_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin_name);
+
+#endif /* MM_MODEM_GOBI_GSM_H */
diff --git a/plugins/mm-modem-hso.c b/plugins/mm-modem-hso.c
new file mode 100644
index 0000000..f1295e2
--- /dev/null
+++ b/plugins/mm-modem-hso.c
@@ -0,0 +1,743 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <dbus/dbus-glib.h>
+
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+
+#include "mm-modem-hso.h"
+#include "mm-modem-simple.h"
+#include "mm-serial-parsers.h"
+#include "mm-errors.h"
+#include "mm-callback-info.h"
+
+static void impl_hso_authenticate (MMModemHso *self,
+ const char *username,
+ const char *password,
+ DBusGMethodInvocation *context);
+
+#include "mm-modem-gsm-hso-glue.h"
+
+static void modem_init (MMModem *modem_class);
+static void modem_simple_init (MMModemSimple *simple_class);
+
+G_DEFINE_TYPE_EXTENDED (MMModemHso, mm_modem_hso, MM_TYPE_GENERIC_GSM, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simple_init))
+
+#define MM_MODEM_HSO_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_HSO, MMModemHsoPrivate))
+
+static void _internal_hso_modem_authenticate (MMModemHso *self, MMCallbackInfo *info);
+
+const char *auth_commands[] = {
+ "$QCPDPP",
+ /* Icera-based devices (GI0322/Quicksilver, iCON 505) don't implement
+ * $QCPDPP, but instead use _OPDPP with the same arguments.
+ */
+ "_OPDPP",
+ NULL
+};
+
+typedef struct {
+ /* Pending connection attempt */
+ MMCallbackInfo *connect_pending_data;
+ guint connect_pending_id;
+
+ guint32 auth_idx;
+} MMModemHsoPrivate;
+
+#define OWANDATA_TAG "_OWANDATA: "
+
+MMModem *
+mm_modem_hso_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_HSO,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_IP_METHOD, MM_MODEM_IP_METHOD_STATIC,
+ NULL));
+}
+
+#define IGNORE_ERRORS_TAG "ignore-errors"
+
+static void
+hso_call_control_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ if (error && !mm_callback_info_get_data (info, IGNORE_ERRORS_TAG))
+ info->error = g_error_copy (error);
+
+ mm_callback_info_schedule (info);
+}
+
+static guint32
+hso_get_cid (MMModemHso *self)
+{
+ guint32 cid;
+
+ cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self));
+ if (cid == 0)
+ cid = 1;
+
+ return cid;
+}
+
+static void
+hso_call_control (MMModemHso *self,
+ gboolean activate,
+ gboolean ignore_errors,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ char *command;
+ MMSerialPort *primary;
+
+ 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);
+}
+
+static void
+connect_pending_done (MMModemHso *self)
+{
+ MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self);
+
+ if (priv->connect_pending_data) {
+ mm_callback_info_schedule (priv->connect_pending_data);
+ priv->connect_pending_data = NULL;
+ }
+
+ if (priv->connect_pending_id) {
+ g_source_remove (priv->connect_pending_id);
+ priv->connect_pending_id = 0;
+ }
+}
+
+static gboolean
+hso_connect_timed_out (gpointer data)
+{
+ MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (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));
+
+ return FALSE;
+}
+
+static void
+hso_enabled (MMModem *modem,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ if (error) {
+ 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);
+ }
+}
+
+static void
+clear_old_context (MMModem *modem,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ 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);
+ }
+}
+
+static void
+auth_done (MMSerialPort *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) {
+ 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);
+ }
+}
+
+static void
+_internal_hso_modem_authenticate (MMModemHso *self, MMCallbackInfo *info)
+{
+ 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");
+
+ 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 : "");
+
+ }
+
+ mm_serial_port_queue_command (primary, command, 3, auth_done, info);
+ g_free (command);
+}
+
+void
+mm_hso_modem_authenticate (MMModemHso *self,
+ const char *username,
+ const char *password,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ 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);
+ 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);
+
+ _internal_hso_modem_authenticate (self, info);
+}
+
+/*****************************************************************************/
+
+static void
+enable_done (MMModem *modem, GError *error, gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info);
+}
+
+static void
+parent_enable_done (MMModem *modem, GError *error, gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMGenericGsm *self = MM_GENERIC_GSM (modem);
+
+ if (error) {
+ mm_generic_gsm_enable_complete (self, error, info);
+ return;
+ }
+
+ /* HSO needs manual PIN checking */
+ mm_generic_gsm_check_pin (self, enable_done, info);
+}
+
+static void
+enable (MMModem *modem, MMModemFn callback, gpointer user_data)
+{
+ MMModem *parent_modem_iface;
+ MMCallbackInfo *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);
+}
+
+static void
+parent_disable_done (MMModem *modem, 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
+disable_done (MMModem *modem,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModem *parent_modem_iface;
+
+ /* Do the normal disable stuff */
+ parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (info->modem));
+ parent_modem_iface->disable (info->modem, parent_disable_done, info);
+}
+
+static void
+disable (MMModem *modem,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (modem));
+
+ info = mm_callback_info_new (modem, callback, user_data);
+
+ /* Kill any existing connection */
+ hso_call_control (MM_MODEM_HSO (modem), FALSE, TRUE, disable_done, info);
+}
+
+static void
+do_connect (MMModem *modem,
+ const char *number,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new (modem, callback, user_data);
+ mm_callback_info_schedule (info);
+}
+
+
+static void
+free_dns_array (gpointer data)
+{
+ g_array_free ((GArray *) data, TRUE);
+}
+
+static void
+ip4_config_invoke (MMCallbackInfo *info)
+{
+ MMModemIp4Fn callback = (MMModemIp4Fn) info->callback;
+
+ callback (info->modem,
+ GPOINTER_TO_UINT (mm_callback_info_get_data (info, "ip4-address")),
+ (GArray *) mm_callback_info_get_data (info, "ip4-dns"),
+ info->error, info->user_data);
+}
+
+static void
+get_ip4_config_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ char **items, **iter;
+ GArray *dns_array;
+ int i;
+ guint32 tmp;
+ guint cid;
+
+ if (error) {
+ info->error = g_error_copy (error);
+ goto out;
+ } else if (!g_str_has_prefix (response->str, OWANDATA_TAG)) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Retrieving failed: invalid response.");
+ goto out;
+ }
+
+ cid = hso_get_cid (MM_MODEM_HSO (info->modem));
+ dns_array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 2);
+ items = g_strsplit (response->str + strlen (OWANDATA_TAG), ", ", 0);
+
+ for (iter = items, i = 0; *iter; iter++, i++) {
+ if (i == 0) { /* CID */
+ long int num;
+
+ errno = 0;
+ num = strtol (*iter, NULL, 10);
+ if (errno != 0 || num < 0 || (guint) 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);
+ break;
+ }
+ } else if (i == 1) { /* IP address */
+ if (inet_pton (AF_INET, *iter, &tmp) > 0)
+ mm_callback_info_set_data (info, "ip4-address", GUINT_TO_POINTER (tmp), NULL);
+ } else if (i == 3) { /* DNS 1 */
+ if (inet_pton (AF_INET, *iter, &tmp) > 0)
+ g_array_append_val (dns_array, tmp);
+ } else if (i == 4) { /* DNS 2 */
+ if (inet_pton (AF_INET, *iter, &tmp) > 0)
+ g_array_append_val (dns_array, tmp);
+ }
+ }
+
+ g_strfreev (items);
+ mm_callback_info_set_data (info, "ip4-dns", dns_array, free_dns_array);
+
+ out:
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_ip4_config (MMModem *modem,
+ MMModemIp4Fn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ char *command;
+ MMSerialPort *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);
+ g_assert (primary);
+ mm_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)
+{
+ MMCallbackInfo *info;
+ MMSerialPort *primary;
+
+ info = mm_callback_info_new (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_OWANCALL=1,0,0", 3, NULL, info);
+}
+
+/*****************************************************************************/
+
+static void
+impl_hso_auth_done (MMModem *modem,
+ GError *error,
+ gpointer user_data)
+{
+ DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
+
+ if (error)
+ dbus_g_method_return_error (context, error);
+ else
+ dbus_g_method_return (context);
+}
+
+static void
+impl_hso_authenticate (MMModemHso *self,
+ const char *username,
+ const char *password,
+ DBusGMethodInvocation *context)
+{
+ /* DBus doesn't support NULLs */
+ if (username && strlen (username) == 0)
+ username = NULL;
+ if (password && strlen (password) == 0)
+ password = NULL;
+
+ 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)
+{
+ GHashTable *properties = (GHashTable *) mm_callback_info_get_data (info, "simple-connect-properties");
+ 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_state_machine (MMModem *modem, GError *error, gpointer user_data)
+{
+ 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;
+ }
+
+ 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);
+}
+
+static void
+simple_connect (MMModemSimple *simple,
+ GHashTable *properties,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ 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);
+
+ simple_state_machine (MM_MODEM (simple), NULL, 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;
+ const char *sys[] = { "tty", "net", NULL };
+ GUdevClient *client;
+ GUdevDevice *device = NULL;
+ MMPort *port = NULL;
+ const char *sysfs_path;
+
+ client = g_udev_client_new (sys);
+ if (!client) {
+ g_set_error (error, 0, 0, "Could not get udev client.");
+ return FALSE;
+ }
+
+ device = g_udev_client_query_by_subsystem_and_name (client, subsys, name);
+ if (!device) {
+ g_set_error (error, 0, 0, "Could not get udev device.");
+ goto out;
+ }
+
+ sysfs_path = g_udev_device_get_sysfs_path (device);
+ if (!sysfs_path) {
+ g_set_error (error, 0, 0, "Could not get udev device sysfs path.");
+ goto out;
+ }
+
+ if (!strcmp (subsys, "tty")) {
+ char *hsotype_path;
+ char *contents = NULL;
+
+ hsotype_path = g_build_filename (sysfs_path, "hsotype", NULL);
+ if (g_file_get_contents (hsotype_path, &contents, NULL, NULL)) {
+ if (g_str_has_prefix (contents, "Control"))
+ ptype = MM_PORT_TYPE_PRIMARY;
+ else if (g_str_has_prefix (contents, "Application") || g_str_has_prefix (contents, "Application2"))
+ ptype = MM_PORT_TYPE_SECONDARY;
+ g_free (contents);
+ }
+ g_free (hsotype_path);
+ }
+
+ port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
+ if (!port)
+ goto out;
+
+ if (MM_IS_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);
+ g_regex_unref (regex);
+ }
+ }
+
+out:
+ if (device)
+ g_object_unref (device);
+ g_object_unref (client);
+ return !!port;
+}
+
+/*****************************************************************************/
+
+static void
+mm_modem_hso_init (MMModemHso *self)
+{
+}
+
+static void
+modem_simple_init (MMModemSimple *class)
+{
+ class->connect = simple_connect;
+}
+
+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)
+{
+ /* Clear the pending connection if necessary */
+ connect_pending_done (MM_MODEM_HSO (object));
+
+ G_OBJECT_CLASS (mm_modem_hso_parent_class)->finalize (object);
+}
+
+static void
+mm_modem_hso_class_init (MMModemHsoClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_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;
+}
+
diff --git a/plugins/mm-modem-hso.h b/plugins/mm-modem-hso.h
new file mode 100644
index 0000000..e2d7623
--- /dev/null
+++ b/plugins/mm-modem-hso.h
@@ -0,0 +1,49 @@
+/* -*- 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_HSO_H
+#define MM_MODEM_HSO_H
+
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_HSO (mm_modem_hso_get_type ())
+#define MM_MODEM_HSO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_HSO, MMModemHso))
+#define MM_MODEM_HSO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_HSO, MMModemHsoClass))
+#define MM_IS_MODEM_HSO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_HSO))
+#define MM_IS_MODEM_HSO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_HSO))
+#define MM_MODEM_HSO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_HSO, MMModemHsoClass))
+
+typedef struct {
+ MMGenericGsm parent;
+} MMModemHso;
+
+typedef struct {
+ MMGenericGsmClass parent;
+} MMModemHsoClass;
+
+GType mm_modem_hso_get_type (void);
+
+MMModem *mm_modem_hso_new (const char *device,
+ const char *driver,
+ const char *plugin);
+
+void mm_hso_modem_authenticate (MMModemHso *self,
+ const char *username,
+ const char *password,
+ MMModemFn callback,
+ gpointer user_data);
+
+#endif /* MM_MODEM_HSO_H */
diff --git a/plugins/mm-modem-huawei-cdma.c b/plugins/mm-modem-huawei-cdma.c
new file mode 100644
index 0000000..3b63a48
--- /dev/null
+++ b/plugins/mm-modem-huawei-cdma.c
@@ -0,0 +1,316 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+
+#include "mm-modem-huawei-cdma.h"
+#include "mm-errors.h"
+#include "mm-callback-info.h"
+#include "mm-serial-port.h"
+#include "mm-serial-parsers.h"
+
+static void modem_init (MMModem *modem_class);
+
+G_DEFINE_TYPE_EXTENDED (MMModemHuaweiCdma, mm_modem_huawei_cdma, MM_TYPE_GENERIC_CDMA, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init))
+
+
+MMModem *
+mm_modem_huawei_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_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,
+ NULL));
+}
+
+/* Unsolicited message handlers */
+
+static gint
+parse_quality (const char *str, const char *detail)
+{
+ long int quality = 0;
+
+ errno = 0;
+ quality = strtol (str, NULL, 10);
+ if (errno == 0) {
+ quality = CLAMP (quality, 0, 100);
+ g_debug ("%s: %ld", detail, quality);
+ return (gint) quality;
+ }
+ return -1;
+}
+
+static void
+handle_1x_quality_change (MMSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data)
+{
+ MMModemHuaweiCdma *self = MM_MODEM_HUAWEI_CDMA (user_data);
+ char *str;
+ gint quality;
+
+ str = g_match_info_fetch (match_info, 1);
+ quality = parse_quality (str, "1X signal quality");
+ g_free (str);
+
+ if (quality >= 0)
+ mm_generic_cdma_update_cdma1x_quality (MM_GENERIC_CDMA (self), (guint32) quality);
+}
+
+static void
+handle_evdo_quality_change (MMSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data)
+{
+ MMModemHuaweiCdma *self = MM_MODEM_HUAWEI_CDMA (user_data);
+ char *str;
+ gint quality;
+
+ str = g_match_info_fetch (match_info, 1);
+ quality = parse_quality (str, "EVDO signal quality");
+ g_free (str);
+
+ if (quality >= 0)
+ mm_generic_cdma_update_evdo_quality (MM_GENERIC_CDMA (self), (guint32) quality);
+}
+
+/*****************************************************************************/
+
+static const char *
+strip_response (const char *resp, const char *cmd)
+{
+ const char *p = resp;
+
+ if (p) {
+ if (!strncmp (p, cmd, strlen (cmd)))
+ p += strlen (cmd);
+ while (*p == ' ')
+ p++;
+ }
+ return p;
+}
+
+static gboolean
+uint_from_match_item (GMatchInfo *match_info, guint32 num, guint32 *val)
+{
+ long int tmp;
+ char *str;
+ gboolean success = FALSE;
+
+ str = g_match_info_fetch (match_info, num);
+ g_return_val_if_fail (str != NULL, FALSE);
+
+ errno = 0;
+ tmp = strtol (str, NULL, 10);
+ if (errno == 0 && tmp >= 0 && tmp <= G_MAXUINT) {
+ *val = (guint32) tmp;
+ success = TRUE;
+ }
+ g_free (str);
+ return success;
+}
+
+static void
+sysinfo_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ 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;
+ }
+
+ reply = strip_response (response->str, "^SYSINFO:");
+
+ /* Format is "<srv_status>,<srv_domain>,<roam_status>,<sys_mode>,<sim_state>" */
+ 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).");
+ goto done;
+ }
+
+ g_regex_match (r, reply, 0, &match_info);
+ if (g_match_info_get_match_count (match_info) >= 5) {
+ MMModemCdmaRegistrationState reg_state;
+ guint32 val = 0;
+
+ /* At this point the generic code already knows we've been registered */
+ reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
+
+ if (uint_from_match_item (match_info, 1, &val)) {
+ if (val == 2) {
+ /* Service available, check roaming state */
+ val = 0;
+ if (uint_from_match_item (match_info, 3, &val)) {
+ if (val == 0)
+ reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_HOME;
+ else if (val == 1)
+ reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING;
+ }
+ }
+ }
+
+ /* Check service type */
+ val = 0;
+ if (uint_from_match_item (match_info, 4, &val)) {
+ if (val == 2)
+ mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state);
+ else if (val == 4)
+ mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, reg_state);
+ else if (val == 8) {
+ 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);
+ }
+ } else {
+ /* 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;
+ }
+
+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.");
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+query_registration_state (MMGenericCdma *cdma,
+ 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);
+
+ 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;
+ }
+
+ mm_serial_port_queue_command (port, "^SYSINFO", 3, sysinfo_done, info);
+}
+
+/*****************************************************************************/
+
+static gboolean
+grab_port (MMModem *modem,
+ const char *subsys,
+ const char *name,
+ MMPortType suggested_type,
+ gpointer user_data,
+ GError **error)
+{
+ MMPort *port = NULL;
+ 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)) {
+ 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);
+ g_regex_unref (regex);
+
+ g_object_get (G_OBJECT (modem),
+ MM_GENERIC_CDMA_EVDO_REV0, &evdo0,
+ MM_GENERIC_CDMA_EVDO_REVA, &evdoA,
+ NULL);
+
+ 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);
+ g_regex_unref (regex);
+ }
+ }
+
+ return !!port;
+}
+
+/*****************************************************************************/
+
+static void
+modem_init (MMModem *modem_class)
+{
+ modem_class->grab_port = grab_port;
+}
+
+static void
+mm_modem_huawei_cdma_init (MMModemHuaweiCdma *self)
+{
+}
+
+static void
+mm_modem_huawei_cdma_class_init (MMModemHuaweiCdmaClass *klass)
+{
+ MMGenericCdmaClass *cdma_class = MM_GENERIC_CDMA_CLASS (klass);
+
+ mm_modem_huawei_cdma_parent_class = g_type_class_peek_parent (klass);
+
+ cdma_class->query_registration_state = query_registration_state;
+}
+
diff --git a/plugins/mm-modem-huawei-cdma.h b/plugins/mm-modem-huawei-cdma.h
new file mode 100644
index 0000000..738f2d9
--- /dev/null
+++ b/plugins/mm-modem-huawei-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 Red Hat, Inc.
+ */
+
+#ifndef MM_MODEM_HUAWEI_CDMA_H
+#define MM_MODEM_HUAWEI_CDMA_H
+
+#include "mm-generic-cdma.h"
+
+#define MM_TYPE_MODEM_HUAWEI_CDMA (mm_modem_huawei_cdma_get_type ())
+#define MM_MODEM_HUAWEI_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_HUAWEI_CDMA, MMModemHuaweiCdma))
+#define MM_MODEM_HUAWEI_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_HUAWEI_CDMA, MMModemHuaweiCdmaClass))
+#define MM_IS_MODEM_HUAWEI_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_HUAWEI_CDMA))
+#define MM_IS_MODEM_HUAWEI_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_HUAWEI_CDMA))
+#define MM_MODEM_HUAWEI_CDMA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_HUAWEI_CDMA, MMModemHuaweiCdmaClass))
+
+typedef struct {
+ MMGenericCdma parent;
+} MMModemHuaweiCdma;
+
+typedef struct {
+ MMGenericCdmaClass parent;
+} MMModemHuaweiCdmaClass;
+
+GType mm_modem_huawei_cdma_get_type (void);
+
+MMModem *mm_modem_huawei_cdma_new (const char *device,
+ const char *driver,
+ const char *plugin,
+ gboolean evdo_rev0,
+ gboolean evdo_revA);
+
+#endif /* MM_MODEM_HUAWEI_CDMA_H */
diff --git a/plugins/mm-modem-huawei-gsm.c b/plugins/mm-modem-huawei-gsm.c
new file mode 100644
index 0000000..d450f25
--- /dev/null
+++ b/plugins/mm-modem-huawei-gsm.c
@@ -0,0 +1,621 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#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-errors.h"
+#include "mm-callback-info.h"
+#include "mm-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);
+
+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))
+
+
+#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;
+} MMModemHuaweiGsmPrivate;
+
+MMModem *
+mm_modem_huawei_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_HUAWEI_GSM,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ NULL));
+}
+
+static gboolean
+parse_syscfg (MMModemHuaweiGsm *self,
+ const char *reply,
+ int *mode_a,
+ int *mode_b,
+ guint32 *band,
+ int *unknown1,
+ int *unknown2)
+{
+ 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);
+
+ /* Network mode */
+ if (*mode_a == 2 && *mode_b == 1)
+ priv->mode = MM_MODEM_GSM_MODE_2G_PREFERRED;
+ else if (*mode_a == 2 && *mode_b == 2)
+ priv->mode = MM_MODEM_GSM_MODE_3G_PREFERRED;
+ else if (*mode_a == 13 && *mode_b == 1)
+ priv->mode = MM_MODEM_GSM_MODE_2G_ONLY;
+ else if (*mode_a == 14 && *mode_b == 2)
+ priv->mode = MM_MODEM_GSM_MODE_3G_ONLY;
+
+ /* 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;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+set_network_mode_done (MMSerialPort *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,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMSerialPort *primary;
+
+ 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_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);
+ return;
+ default:
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Invalid mode.");
+ break;
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_network_mode_done (MMSerialPort *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->mode), NULL);
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_network_mode (MMModemGsmNetwork *modem,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (modem);
+
+ 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 (modem), callback, user_data);
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->mode), NULL);
+ 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);
+ }
+}
+
+static void
+set_band_done (MMSerialPort *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->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;
+
+ 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);
+ return;
+ default:
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Invalid band.");
+ break;
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_band_done (MMSerialPort *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);
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_band (MMModemGsmNetwork *modem,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (modem);
+ MMSerialPort *primary;
+
+ if (priv->band != MM_MODEM_GSM_BAND_ANY) {
+ /* have cached mode (from an unsolicited message). Use that */
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->band), NULL);
+ mm_callback_info_schedule (info);
+ } else {
+ /* Get it from modem */
+ MMCallbackInfo *info;
+
+ 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);
+ }
+}
+
+static void
+get_signal_quality (MMModemGsmNetwork *modem,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (modem);
+
+ if (priv->signal_quality) {
+ /* have cached signal quality (from an unsolicited message). Use that */
+ MMCallbackInfo *info;
+
+ 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);
+ mm_callback_info_schedule (info);
+ } else {
+ /* Use the generic implementation */
+ MMModemGsmNetwork *parent_gsm_network_iface;
+
+ 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);
+ }
+}
+
+/* Unsolicited message handlers */
+
+static void
+handle_signal_quality_change (MMSerialPort *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;
+
+ 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 = quality * 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);
+}
+
+static void
+handle_mode_change (MMSerialPort *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 a;
+ int b;
+
+ str = g_match_info_fetch (match_info, 1);
+ a = atoi (str);
+ g_free (str);
+
+ str = g_match_info_fetch (match_info, 2);
+ b = atoi (str);
+ 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;
+ 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);
+}
+
+static void
+handle_status_change (MMSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data)
+{
+ char *str;
+ int n1, n2, n3, n4, n5, n6, n7;
+
+ str = g_match_info_fetch (match_info, 1);
+ if (sscanf (str, "%x,%x,%x,%x,%x,%x,%x", &n1, &n2, &n3, &n4, &n5, &n6, &n7)) {
+ g_debug ("Duration: %d Up: %d Kbps Down: %d Kbps Total: %d Total: %d\n",
+ n1, n2 * 8 / 1000, n3 * 8 / 1000, n4 / 1024, n5 / 1024);
+ }
+ g_free (str);
+}
+
+/*****************************************************************************/
+
+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;
+ const char *sys[] = { "tty", NULL };
+ GUdevClient *client;
+ GUdevDevice *device = NULL;
+ MMPort *port = NULL;
+ int usbif;
+
+ client = g_udev_client_new (sys);
+ if (!client) {
+ g_set_error (error, 0, 0, "Could not get udev client.");
+ return FALSE;
+ }
+
+ device = g_udev_client_query_by_subsystem_and_name (client, subsys, name);
+ if (!device) {
+ g_set_error (error, 0, 0, "Could not get udev device.");
+ goto out;
+ }
+
+ usbif = g_udev_device_get_property_as_int (device, "ID_USB_INTERFACE_NUM");
+ if (usbif < 0) {
+ g_set_error (error, 0, 0, "Could not get USB device interface number.");
+ goto out;
+ }
+
+ if (usbif == 0) {
+ if (!mm_generic_gsm_get_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))
+ 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;
+
+ mm_generic_gsm_set_unsolicited_registration (MM_GENERIC_GSM (modem), TRUE);
+
+ 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\\^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\\^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\\^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);
+ }
+ }
+
+out:
+ if (device)
+ g_object_unref (device);
+ g_object_unref (client);
+ return !!port;
+}
+
+/*****************************************************************************/
+
+static void
+modem_init (MMModem *modem_class)
+{
+ modem_class->grab_port = grab_port;
+}
+
+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
+mm_modem_huawei_gsm_init (MMModemHuaweiGsm *self)
+{
+}
+
+static void
+mm_modem_huawei_gsm_class_init (MMModemHuaweiGsmClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ mm_modem_huawei_gsm_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (object_class, sizeof (MMModemHuaweiGsmPrivate));
+}
+
diff --git a/plugins/mm-modem-huawei-gsm.h b/plugins/mm-modem-huawei-gsm.h
new file mode 100644
index 0000000..9c2ec34
--- /dev/null
+++ b/plugins/mm-modem-huawei-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_HUAWEI_GSM_H
+#define MM_MODEM_HUAWEI_GSM_H
+
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_HUAWEI_GSM (mm_modem_huawei_gsm_get_type ())
+#define MM_MODEM_HUAWEI_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_HUAWEI_GSM, MMModemHuaweiGsm))
+#define MM_MODEM_HUAWEI_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_HUAWEI_GSM, MMModemHuaweiGsmClass))
+#define MM_IS_MODEM_HUAWEI_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_HUAWEI_GSM))
+#define MM_IS_MODEM_HUAWEI_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_HUAWEI_GSM))
+#define MM_MODEM_HUAWEI_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_HUAWEI_GSM, MMModemHuaweiGsmClass))
+
+typedef struct {
+ MMGenericGsm parent;
+} MMModemHuaweiGsm;
+
+typedef struct {
+ MMGenericGsmClass parent;
+} MMModemHuaweiGsmClass;
+
+GType mm_modem_huawei_gsm_get_type (void);
+
+MMModem *mm_modem_huawei_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin);
+
+#endif /* MM_MODEM_HUAWEI_GSM_H */
diff --git a/plugins/mm-modem-mbm.c b/plugins/mm-modem-mbm.c
new file mode 100644
index 0000000..686b35c
--- /dev/null
+++ b/plugins/mm-modem-mbm.c
@@ -0,0 +1,830 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2008 Ericsson AB
+ *
+ * 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>
+ *
+ * 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.
+ *
+ * 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>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mm-modem-mbm.h"
+#include "mm-modem-simple.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);
+
+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))
+
+#define MM_MODEM_MBM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_MBM, MMModemMbmPrivate))
+
+#define MBM_E2NAP_DISCONNECTED 0
+#define MBM_E2NAP_CONNECTED 1
+#define MBM_E2NAP_CONNECTING 2
+
+#define MBM_SIGNAL_INDICATOR 2
+
+#define MBM_NETWORK_MODE_ANY 1
+#define MBM_NETWORK_MODE_2G 5
+#define MBM_NETWORK_MODE_3G 6
+
+#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;
+ char *network_device;
+ MMCallbackInfo *pending_connect_info;
+ int account_index;
+ int network_mode;
+ const char *username;
+ const char *password;
+} MMModemMbmPrivate;
+
+enum {
+ PROP_0,
+ PROP_NETWORK_DEVICE,
+
+ LAST_PROP
+};
+
+static void
+mbm_modem_authenticate (MMModemMbm *self,
+ const char *username,
+ 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,
+ 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_MBM,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ MM_MODEM_IP_METHOD, MM_MODEM_IP_METHOD_DHCP,
+ NULL));
+}
+
+/*****************************************************************************/
+/* Gsm network class override functions */
+/*****************************************************************************/
+
+typedef struct {
+ MMModemGsmNetwork *modem;
+ const char *network_id;
+ MMModemFn callback;
+ gpointer user_data;
+} RegisterData;
+
+static gboolean
+register_done (gpointer user_data)
+{
+ RegisterData *reg_data = 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,
+ reg_data->callback,
+ reg_data->user_data);
+ return FALSE;
+}
+
+static void
+do_register (MMModemGsmNetwork *modem,
+ const char *network_id,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMModemMbm *self = MM_MODEM_MBM (modem);
+ MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
+ RegisterData *reg_data;
+
+ reg_data = g_malloc0 (sizeof(RegisterData));
+ reg_data->modem = modem;
+ reg_data->network_id = network_id;
+ reg_data->callback = callback;
+ reg_data->user_data = user_data;
+
+ /* wait so sim pin is done */
+ if (priv->reg_id)
+ g_source_remove (priv->reg_id);
+ priv->reg_id = g_timeout_add_full (G_PRIORITY_DEFAULT, 500,
+ register_done, reg_data,
+ g_free);
+}
+
+static int
+mbm_parse_network_mode (MMModemGsmMode 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:
+ return MBM_NETWORK_MODE_ANY;
+ case MM_MODEM_GSM_MODE_GPRS:
+ case MM_MODEM_GSM_MODE_EDGE:
+ case MM_MODEM_GSM_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:
+ return MBM_NETWORK_MODE_3G;
+ default:
+ return MBM_NETWORK_MODE_ANY;
+ }
+}
+
+static void
+mbm_set_network_mode_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);
+}
+
+static void
+set_network_mode (MMModemGsmNetwork *modem,
+ MMModemGsmMode mode,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ char *command;
+ MMSerialPort *primary;
+
+ 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);
+
+ 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);
+ g_free (command);
+}
+
+static void
+get_network_mode_done (MMSerialPort *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) {
+ 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;
+
+ 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);
+
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mm_mode), NULL);
+ parsed = TRUE;
+ }
+
+done:
+ 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)
+{
+ 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, "*ERINFO?", 3, get_network_mode_done, info);
+}
+
+/*****************************************************************************/
+/* Simple Modem class override functions */
+/*****************************************************************************/
+
+static void
+simple_connect (MMModemSimple *simple,
+ GHashTable *properties,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ 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);
+}
+
+/*****************************************************************************/
+/* Modem class override functions */
+/*****************************************************************************/
+
+static void
+mbm_enable_done (MMSerialPort *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);
+}
+
+static void
+mbm_enap0_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (info->modem);
+ char *command;
+
+ if (!priv->network_mode)
+ 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);
+ g_free (command);
+}
+
+static void
+mbm_init_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (info->modem);
+
+ if (error) {
+ mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
+ return;
+ }
+
+ if (!priv->network_mode)
+ priv->network_mode = MBM_NETWORK_MODE_ANY;
+
+ mm_serial_port_queue_command (port, "*ENAP=0", 3, mbm_enap0_done, info);
+}
+
+static void
+do_init (MMSerialPort *port, MMCallbackInfo *info)
+{
+ mm_serial_port_queue_command (port, "&F E0 V1 X4 &C1 +CMEE=1", 3, mbm_init_done, info);
+}
+
+static void
+mbm_emrdy_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ 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) {
+ g_warning ("%s: timed out waiting for EMRDY response.", __func__);
+ } else
+ priv->have_emrdy = TRUE;
+
+ do_init (port, info);
+}
+
+static void
+do_enable (MMGenericGsm *self, MMModemFn callback, gpointer user_data)
+{
+ MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
+ MMCallbackInfo *info;
+ MMSerialPort *primary;
+
+ info = mm_callback_info_new (MM_MODEM (self), callback, user_data);
+
+ primary = mm_generic_gsm_get_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);
+}
+
+typedef struct {
+ MMModem *modem;
+ MMModemFn callback;
+ gpointer user_data;
+} DisableInfo;
+
+static void
+disable_creg_cmer_done (MMSerialPort *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)
+{
+ MMSerialPort *primary;
+ DisableInfo *info;
+
+ info = g_malloc0 (sizeof (DisableInfo));
+ info->callback = callback;
+ info->user_data = user_data;
+ info->modem = modem;
+
+ primary = mm_generic_gsm_get_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);
+}
+
+static void
+do_connect (MMModem *modem,
+ const char *number,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (modem);
+
+ mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE);
+
+ info = mm_callback_info_new (modem, callback, user_data);
+ priv->pending_connect_info = info;
+
+ mbm_modem_authenticate (MM_MODEM_MBM (modem), priv->username, priv->password, info);
+}
+
+static void
+disconnect (MMModem *modem,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMSerialPort *primary;
+
+ mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE);
+
+ primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+ mm_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);
+
+ info = mm_callback_info_new (modem, callback, user_data);
+ mm_callback_info_schedule (info);
+}
+
+/*****************************************************************************/
+
+static void
+mbm_emrdy_received (MMSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data)
+{
+ MM_MODEM_MBM_GET_PRIVATE (user_data)->have_emrdy = TRUE;
+}
+
+static void
+mbm_pacsp_received (MMSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data)
+{
+ return;
+}
+
+static void
+mbm_ciev_received (MMSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data)
+{
+ int quality = 0, ind = 0;
+ const char *str;
+
+ str = g_match_info_fetch (info, 1);
+ if (str)
+ ind = atoi (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);
+ }
+ }
+}
+
+static void
+mbm_do_connect_done (MMModemMbm *self)
+{
+ MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
+
+ if (priv->pending_connect_info) {
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (self), NULL, priv->pending_connect_info);
+ priv->pending_connect_info = NULL;
+ }
+}
+
+static void
+mbm_e2nap_received (MMSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data)
+{
+ int state = 0;
+ const 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));
+ } else if (MBM_E2NAP_CONNECTING == state)
+ g_debug("%s, connecting", __func__);
+ else {
+ /* Should not happen */
+ g_debug("%s, undefined e2nap status",__FUNCTION__);
+ g_assert_not_reached ();
+ }
+}
+
+static void
+enap_poll_response (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ guint state;
+ guint count;
+
+ g_assert (info);
+
+ count = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "mbm-enap-poll-count"));
+
+ if (sscanf (response->str, "*ENAP: %d", &state) == 1 && state == 1) {
+ /* Success! Connected... */
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), NULL, info);
+ return;
+ }
+
+ mm_callback_info_set_data (info, "mbm-enap-poll-count", GUINT_TO_POINTER (++count), NULL);
+
+ /* lets give it about 50 seconds */
+ if (count > 50) {
+ GError *poll_error;
+
+ poll_error = mm_modem_connect_error_for_code (MM_MODEM_CONNECT_ERROR_BUSY);
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), poll_error, info);
+ g_error_free (poll_error);
+ }
+}
+
+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);
+
+ g_assert (port);
+
+ mm_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)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ guint tid;
+
+ if (error) {
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), error, info);
+ return;
+ }
+
+ 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,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMGenericGsm *modem = MM_GENERIC_GSM (info->modem);
+ char *command;
+ guint32 cid;
+
+ if (error) {
+ mm_generic_gsm_connect_complete (modem, error, info);
+ return;
+ }
+
+ cid = mm_generic_gsm_get_cid (modem);
+ command = g_strdup_printf ("AT*ENAP=1,%d", cid);
+ mm_serial_port_queue_command (port, command, 3, enap_done, user_data);
+ g_free (command);
+}
+
+static void
+mbm_modem_authenticate (MMModemMbm *self,
+ const char *username,
+ const char *password,
+ gpointer user_data)
+{
+ MMSerialPort *primary;
+
+ primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
+ if (username || password) {
+ char *command;
+
+ command = g_strdup_printf ("*EIAAUW=%d,1,\"%s\",\"%s\"",
+ mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)),
+ username ? username : "",
+ password ? password : "");
+
+ mm_serial_port_queue_command (primary, command, 3, mbm_auth_done, user_data);
+ g_free (command);
+ } else
+ mbm_auth_done (primary, NULL, NULL, user_data);
+}
+
+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 uint
+mbm_simple_get_uint_property (GHashTable *properties, const char *name, GError **error)
+{
+ GValue *value;
+
+ value = (GValue *) g_hash_table_lookup (properties, name);
+ if (!value)
+ return 0;
+
+ if (G_VALUE_HOLDS_UINT (value))
+ return g_value_get_uint (value);
+
+ 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));
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+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 (!strcmp (subsys, "tty")) {
+ 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;
+ }
+
+ port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
+ if (port && MM_IS_SERIAL_PORT (port) && (ptype == MM_PORT_TYPE_PRIMARY)) {
+ GRegex *regex;
+
+ mm_generic_gsm_set_unsolicited_registration (MM_GENERIC_GSM (modem), TRUE);
+
+ 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);
+
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ g_regex_unref (regex);
+ }
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+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
+modem_simple_init (MMModemSimple *class)
+{
+ class->connect = simple_connect;
+}
+
+static void
+modem_init (MMModem *modem_class)
+{
+ modem_class->grab_port = grab_port;
+ modem_class->disable = disable;
+ modem_class->connect = do_connect;
+ modem_class->disconnect = disconnect;
+}
+
+static void
+mm_modem_mbm_init (MMModemMbm *self)
+{
+}
+
+static void
+finalize (GObject *object)
+{
+ MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (object);
+
+ if (priv->reg_id)
+ g_source_remove (priv->reg_id);
+
+ g_free (priv->network_device);
+
+ G_OBJECT_CLASS (mm_modem_mbm_parent_class)->finalize (object);
+}
+
+static void
+mm_modem_mbm_class_init (MMModemMbmClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
+
+ mm_modem_mbm_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (object_class, sizeof (MMModemMbmPrivate));
+
+ /* Virtual methods */
+ object_class->finalize = finalize;
+
+ gsm_class->do_enable = do_enable;
+}
+
diff --git a/plugins/mm-modem-mbm.h b/plugins/mm-modem-mbm.h
new file mode 100644
index 0000000..8756e47
--- /dev/null
+++ b/plugins/mm-modem-mbm.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2008 Ericsson AB
+ *
+ * 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>
+ *
+ * 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.
+ *
+ * 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
+#define MM_MODEM_MBM_H
+
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_MBM (mm_modem_mbm_get_type ())
+#define MM_MODEM_MBM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_MBM, MMModemMbm))
+#define MM_MODEM_MBM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_MBM, MMModemMbmClass))
+#define MM_IS_MODEM_MBM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_MBM))
+#define MM_IS_MODEM_MBM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_MBM))
+#define MM_MODEM_MBM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_MBM, MMModemMbmClass))
+
+typedef struct {
+ MMGenericGsm parent;
+} MMModemMbm;
+
+typedef struct {
+ MMGenericGsmClass parent;
+} MMModemMbmClass;
+
+GType mm_modem_mbm_get_type (void);
+
+MMModem *mm_modem_mbm_new (const char *device,
+ const char *driver,
+ const char *plugin_name);
+
+#endif /* MM_MODEM_MBM_H */
diff --git a/plugins/mm-modem-moto-c-gsm.c b/plugins/mm-modem-moto-c-gsm.c
new file mode 100644
index 0000000..5910ff2
--- /dev/null
+++ b/plugins/mm-modem-moto-c-gsm.c
@@ -0,0 +1,129 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mm-modem-moto-c-gsm.h"
+#include "mm-errors.h"
+#include "mm-callback-info.h"
+#include "mm-modem-gsm-card.h"
+
+static void modem_init (MMModem *modem_class);
+static void modem_gsm_card_init (MMModemGsmCard *gsm_card_class);
+
+G_DEFINE_TYPE_EXTENDED (MMModemMotoCGsm, mm_modem_moto_c_gsm, MM_TYPE_GENERIC_GSM, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_CARD, modem_gsm_card_init))
+
+
+MMModem *
+mm_modem_moto_c_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_MOTO_C_GSM,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ NULL));
+}
+
+/*****************************************************************************/
+
+static void
+modem_init (MMModem *modem_class)
+{
+}
+
+/*****************************************************************************/
+
+static void
+get_imei (MMModemGsmCard *modem,
+ MMModemStringFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_OPERATION_NOT_SUPPORTED,
+ "Operation not supported");
+ mm_callback_info_schedule (info);
+}
+
+static void
+modem_gsm_card_init (MMModemGsmCard *class)
+{
+ class->get_imei = get_imei;
+}
+
+/*****************************************************************************/
+
+static void
+mm_modem_moto_c_gsm_init (MMModemMotoCGsm *self)
+{
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+
+ /* These devices just don't implement AT+CFUN */
+
+ switch (prop_id) {
+ case MM_GENERIC_GSM_PROP_POWER_UP_CMD:
+ g_value_set_string (value, "");
+ break;
+ case MM_GENERIC_GSM_PROP_POWER_DOWN_CMD:
+ g_value_set_string (value, "");
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+}
+
+static void
+mm_modem_moto_c_gsm_class_init (MMModemMotoCGsmClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ mm_modem_moto_c_gsm_parent_class = g_type_class_peek_parent (klass);
+
+ object_class->get_property = get_property;
+ object_class->set_property = set_property;
+
+ g_object_class_override_property (object_class,
+ MM_GENERIC_GSM_PROP_POWER_UP_CMD,
+ MM_GENERIC_GSM_POWER_UP_CMD);
+
+ g_object_class_override_property (object_class,
+ MM_GENERIC_GSM_PROP_POWER_DOWN_CMD,
+ MM_GENERIC_GSM_POWER_DOWN_CMD);
+}
+
diff --git a/plugins/mm-modem-moto-c-gsm.h b/plugins/mm-modem-moto-c-gsm.h
new file mode 100644
index 0000000..eb1dad1
--- /dev/null
+++ b/plugins/mm-modem-moto-c-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_MOTO_C_GSM_H
+#define MM_MODEM_MOTO_C_GSM_H
+
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_MOTO_C_GSM (mm_modem_moto_c_gsm_get_type ())
+#define MM_MODEM_MOTO_C_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_MOTO_C_GSM, MMModemMotoCGsm))
+#define MM_MODEM_MOTO_C_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_MOTO_C_GSM, MMModemMotoCGsmClass))
+#define MM_IS_MODEM_MOTO_C_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_MOTO_C_GSM))
+#define MM_IS_MODEM_MOTO_C_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_MOTO_C_GSM))
+#define MM_MODEM_MOTO_C_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_MOTO_C_GSM, MMModemMotoCGsmClass))
+
+typedef struct {
+ MMGenericGsm parent;
+} MMModemMotoCGsm;
+
+typedef struct {
+ MMGenericGsmClass parent;
+} MMModemMotoCGsmClass;
+
+GType mm_modem_moto_c_gsm_get_type (void);
+
+MMModem *mm_modem_moto_c_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin_name);
+
+#endif /* MM_MODEM_MOTO_C_GSM_H */
diff --git a/plugins/mm-modem-nokia.c b/plugins/mm-modem-nokia.c
new file mode 100644
index 0000000..677a089
--- /dev/null
+++ b/plugins/mm-modem-nokia.c
@@ -0,0 +1,142 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "mm-modem-nokia.h"
+#include "mm-serial-parsers.h"
+
+static void modem_init (MMModem *modem_class);
+
+G_DEFINE_TYPE_EXTENDED (MMModemNokia, mm_modem_nokia, MM_TYPE_GENERIC_GSM, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init))
+
+
+MMModem *
+mm_modem_nokia_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_NOKIA,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ NULL));
+}
+
+static gboolean
+grab_port (MMModem *modem,
+ const char *subsys,
+ const char *name,
+ MMPortType suggested_type,
+ gpointer user_data,
+ GError **error)
+{
+ MMGenericGsm *gsm = MM_GENERIC_GSM (modem);
+ MMPortType ptype = MM_PORT_TYPE_IGNORED;
+ MMPort *port = NULL;
+
+ if (suggested_type == MM_PORT_TYPE_UNKNOWN) {
+ if (!mm_generic_gsm_get_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;
+
+ 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);
+ }
+
+ return !!port;
+}
+
+/*****************************************************************************/
+
+static void
+modem_init (MMModem *modem_class)
+{
+ modem_class->grab_port = grab_port;
+}
+
+static void
+mm_modem_nokia_init (MMModemNokia *self)
+{
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ /* gobject does not like to just have get_property and seems to
+ * to not honour our overriden properties ... keep this as an empty
+ * func around */
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ /* Nokia headsets (at least N85) do not support "power on"; they do
+ * support "power off" but you proabably do not want to turn off the
+ * power on your telephone if something went wrong with connecting
+ * process. So, disabling both these operations. The Nokia GSM/UMTS command
+ * reference v1.2 also states that only CFUN=0 (turn off but still charge)
+ * and CFUN=1 (full functionality) are supported, and since the phone has
+ * to be in CFUN=1 before we'll be able to talk to it in the first place,
+ * we shouldn't bother with CFUN at all.
+ */
+ switch (prop_id) {
+ case MM_GENERIC_GSM_PROP_POWER_UP_CMD:
+ g_value_set_string (value, "");
+ break;
+ case MM_GENERIC_GSM_PROP_POWER_DOWN_CMD:
+ g_value_set_string (value, "");
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+mm_modem_nokia_class_init (MMModemNokiaClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ mm_modem_nokia_parent_class = g_type_class_peek_parent (klass);
+
+ object_class->get_property = get_property;
+ object_class->set_property = set_property;
+
+ g_object_class_override_property (object_class,
+ MM_GENERIC_GSM_PROP_POWER_UP_CMD,
+ MM_GENERIC_GSM_POWER_UP_CMD);
+
+ g_object_class_override_property (object_class,
+ MM_GENERIC_GSM_PROP_POWER_DOWN_CMD,
+ MM_GENERIC_GSM_POWER_DOWN_CMD);
+}
+
diff --git a/plugins/mm-modem-nokia.h b/plugins/mm-modem-nokia.h
new file mode 100644
index 0000000..0e24619
--- /dev/null
+++ b/plugins/mm-modem-nokia.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_NOKIA_H
+#define MM_MODEM_NOKIA_H
+
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_NOKIA (mm_modem_nokia_get_type ())
+#define MM_MODEM_NOKIA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_NOKIA, MMModemNokia))
+#define MM_MODEM_NOKIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_NOKIA, MMModemNokiaClass))
+#define MM_IS_MODEM_NOKIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_NOKIA))
+#define MM_IS_MODEM_NOKIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_NOKIA))
+#define MM_MODEM_NOKIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_NOKIA, MMModemNokiaClass))
+
+typedef struct {
+ MMGenericGsm parent;
+} MMModemNokia;
+
+typedef struct {
+ MMGenericGsmClass parent;
+} MMModemNokiaClass;
+
+GType mm_modem_nokia_get_type (void);
+
+MMModem *mm_modem_nokia_new (const char *data,
+ const char *driver,
+ const char *plugin);
+
+#endif /* MM_MODEM_NOKIA_H */
diff --git a/plugins/mm-modem-novatel-gsm.c b/plugins/mm-modem-novatel-gsm.c
new file mode 100644
index 0000000..8189627
--- /dev/null
+++ b/plugins/mm-modem-novatel-gsm.c
@@ -0,0 +1,184 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "mm-modem-novatel-gsm.h"
+#include "mm-errors.h"
+#include "mm-callback-info.h"
+
+static void modem_init (MMModem *modem_class);
+
+G_DEFINE_TYPE_EXTENDED (MMModemNovatelGsm, mm_modem_novatel_gsm, MM_TYPE_GENERIC_GSM, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init))
+
+
+MMModem *
+mm_modem_novatel_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_NOVATEL_GSM,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ NULL));
+}
+
+/*****************************************************************************/
+/* Modem class override functions */
+/*****************************************************************************/
+
+static void
+init_modem_done (MMSerialPort *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);
+}
+
+static void
+pin_check_done (MMModem *modem, 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;
+ }
+
+ /* 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);
+}
+
+static void
+pre_init_done (MMSerialPort *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);
+ 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);
+}
+
+static void
+enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
+{
+ MMCallbackInfo *info = 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);
+}
+
+static void
+do_enable (MMGenericGsm *modem, MMModemFn callback, gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMSerialPort *primary;
+
+ primary = mm_generic_gsm_get_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);
+}
+
+static void
+dmat_callback (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ mm_serial_port_close (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_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;
+
+ 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);
+ }
+
+ return !!port;
+}
+
+/*****************************************************************************/
+
+static void
+modem_init (MMModem *modem_class)
+{
+ modem_class->grab_port = grab_port;
+}
+
+static void
+mm_modem_novatel_gsm_init (MMModemNovatelGsm *self)
+{
+}
+
+static void
+mm_modem_novatel_gsm_class_init (MMModemNovatelGsmClass *klass)
+{
+ MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
+
+ mm_modem_novatel_gsm_parent_class = g_type_class_peek_parent (klass);
+
+ gsm_class->do_enable = do_enable;
+}
+
diff --git a/plugins/mm-modem-novatel-gsm.h b/plugins/mm-modem-novatel-gsm.h
new file mode 100644
index 0000000..c2e1138
--- /dev/null
+++ b/plugins/mm-modem-novatel-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_NOVATEL_GSM_H
+#define MM_MODEM_NOVATEL_GSM_H
+
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_NOVATEL_GSM (mm_modem_novatel_gsm_get_type ())
+#define MM_MODEM_NOVATEL_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_NOVATEL_GSM, MMModemNovatelGsm))
+#define MM_MODEM_NOVATEL_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_NOVATEL_GSM, MMModemNovatelGsmClass))
+#define MM_IS_MODEM_NOVATEL_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_NOVATEL_GSM))
+#define MM_IS_MODEM_NOVATEL_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_NOVATEL_GSM))
+#define MM_MODEM_NOVATEL_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_NOVATEL_GSM, MMModemNovatelGsmClass))
+
+typedef struct {
+ MMGenericGsm parent;
+} MMModemNovatelGsm;
+
+typedef struct {
+ MMGenericGsmClass parent;
+} MMModemNovatelGsmClass;
+
+GType mm_modem_novatel_gsm_get_type (void);
+
+MMModem *mm_modem_novatel_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin_name);
+
+#endif /* MM_MODEM_NOVATEL_GSM_H */
diff --git a/plugins/mm-modem-option.c b/plugins/mm-modem-option.c
new file mode 100644
index 0000000..2076ae6
--- /dev/null
+++ b/plugins/mm-modem-option.c
@@ -0,0 +1,244 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "mm-modem-option.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);
+
+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))
+
+
+MMModem *
+mm_modem_option_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_OPTION,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ NULL));
+}
+
+/*****************************************************************************/
+
+static void
+pin_check_done (MMModem *modem, GError *error, gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info);
+}
+
+static gboolean
+option_enabled (gpointer data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) data;
+
+ /* 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);
+ return FALSE;
+}
+
+static void
+parent_enable_done (MMModem *modem, GError *error, gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ if (error) {
+ mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info);
+ return;
+ }
+
+ /* Option returns OK on +CFUN=1 right away but needs some time
+ * to finish initialization
+ */
+ g_timeout_add_seconds (10, option_enabled, info);
+}
+
+static void
+enable (MMModem *modem,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMModem *parent_modem_iface;
+ 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);
+}
+
+static void
+get_network_mode_done (MMSerialPort *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)) {
+ 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)
+{
+ 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_OPSYS?", 3, get_network_mode_done, info);
+}
+
+static void
+set_network_mode_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);
+}
+
+static void
+set_network_mode (MMModemGsmNetwork *modem,
+ MMModemGsmMode mode,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ 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;
+ }
+
+ 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);
+}
+
+/*****************************************************************************/
+
+static void
+modem_init (MMModem *modem_class)
+{
+ modem_class->enable = enable;
+}
+
+static void
+modem_gsm_network_init (MMModemGsmNetwork *class)
+{
+ class->set_network_mode = set_network_mode;
+ class->get_network_mode = get_network_mode;
+}
+
+static void
+mm_modem_option_init (MMModemOption *self)
+{
+}
+
+static void
+mm_modem_option_class_init (MMModemOptionClass *klass)
+{
+ mm_modem_option_parent_class = g_type_class_peek_parent (klass);
+}
+
diff --git a/plugins/mm-modem-option.h b/plugins/mm-modem-option.h
new file mode 100644
index 0000000..4e88607
--- /dev/null
+++ b/plugins/mm-modem-option.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_OPTION_H
+#define MM_MODEM_OPTION_H
+
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_OPTION (mm_modem_option_get_type ())
+#define MM_MODEM_OPTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_OPTION, MMModemOption))
+#define MM_MODEM_OPTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_OPTION, MMModemOptionClass))
+#define MM_IS_MODEM_OPTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_OPTION))
+#define MM_IS_MODEM_OPTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_OPTION))
+#define MM_MODEM_OPTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_OPTION, MMModemOptionClass))
+
+typedef struct {
+ MMGenericGsm parent;
+} MMModemOption;
+
+typedef struct {
+ MMGenericGsmClass parent;
+} MMModemOptionClass;
+
+GType mm_modem_option_get_type (void);
+
+MMModem *mm_modem_option_new (const char *device,
+ const char *driver,
+ const char *plugin_name);
+
+#endif /* MM_MODEM_OPTION_H */
diff --git a/plugins/mm-modem-sierra-cdma.c b/plugins/mm-modem-sierra-cdma.c
new file mode 100644
index 0000000..4f3140b
--- /dev/null
+++ b/plugins/mm-modem-sierra-cdma.c
@@ -0,0 +1,383 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+
+#include "mm-modem-sierra-cdma.h"
+#include "mm-errors.h"
+#include "mm-callback-info.h"
+#include "mm-serial-port.h"
+#include "mm-serial-parsers.h"
+
+G_DEFINE_TYPE (MMModemSierraCdma, mm_modem_sierra_cdma, MM_TYPE_GENERIC_CDMA)
+
+#define MM_MODEM_SIERRA_CDMA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_SIERRA_CDMA, MMModemSierraCdmaPrivate))
+
+typedef enum {
+ SYS_MODE_UNKNOWN,
+ SYS_MODE_NO_SERVICE,
+ SYS_MODE_CDMA_1X,
+ SYS_MODE_EVDO_REV0,
+ SYS_MODE_EVDO_REVA
+} SysMode;
+
+typedef struct {
+ SysMode sys_mode;
+} MMModemSierraCdmaPrivate;
+
+MMModem *
+mm_modem_sierra_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_SIERRA_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));
+}
+
+/*****************************************************************************/
+
+#define MODEM_REG_TAG "Modem has registered"
+#define GENERIC_ROAM_TAG "Roaming:"
+#define ROAM_1X_TAG "1xRoam:"
+#define ROAM_EVDO_TAG "HDRRoam:"
+#define SYS_MODE_TAG "Sys Mode:"
+#define SYS_MODE_NO_SERVICE_TAG "NO SRV"
+#define SYS_MODE_EVDO_TAG "HDR"
+#define SYS_MODE_1X_TAG "1x"
+#define EVDO_REV_TAG "HDR Revision:"
+#define SID_TAG "SID:"
+
+static gboolean
+get_roam_value (const char *reply, const char *tag, gboolean *roaming)
+{
+ char *p;
+
+ p = strstr (reply, tag);
+ if (!p)
+ return FALSE;
+
+ p += strlen (tag);
+ while (*p && isspace (*p))
+ p++;
+ if (*p == '1') {
+ *roaming = TRUE;
+ return TRUE;
+ } else if (*p == '0') {
+ *roaming = FALSE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+sys_mode_has_service (SysMode mode)
+{
+ return ( mode == SYS_MODE_CDMA_1X
+ || mode == SYS_MODE_EVDO_REV0
+ || mode == SYS_MODE_EVDO_REVA);
+}
+
+static void
+status_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemSierraCdmaPrivate *priv = MM_MODEM_SIERRA_CDMA_GET_PRIVATE (info->modem);
+ char **lines, **iter;
+ gboolean registered = FALSE;
+ gboolean have_sid = FALSE;
+ SysMode evdo_mode = SYS_MODE_UNKNOWN;
+ SysMode sys_mode = SYS_MODE_UNKNOWN;
+ gboolean cdma_1x_set = FALSE, evdo_set = FALSE;
+
+ if (error) {
+ info->error = g_error_copy (error);
+ goto done;
+ }
+
+ lines = g_strsplit_set (response->str, "\n\r", 0);
+ if (!lines) {
+ /* Whatever, just use default registration state */
+ goto done;
+ }
+
+ /* Sierra CDMA parts have two general formats depending on whether they
+ * support EVDO or not. EVDO parts report both 1x and EVDO roaming status
+ * while of course 1x parts only report 1x status. Some modems also do not
+ * report the Roaming information (MP 555 GPS).
+ *
+ * AT!STATUS responses:
+ *
+ * Unregistered MC5725:
+ * -----------------------
+ * Current band: PCS CDMA
+ * Current channel: 350
+ * SID: 0 NID: 0 1xRoam: 0 HDRRoam: 0
+ * Temp: 33 State: 100 Sys Mode: NO SRV
+ * Pilot NOT acquired
+ * Modem has NOT registered
+ *
+ * Registered MC5725:
+ * -----------------------
+ * Current band: Cellular Sleep
+ * Current channel: 775
+ * SID: 30 NID: 2 1xRoam: 0 HDRRoam: 0
+ * Temp: 29 State: 200 Sys Mode: HDR
+ * Pilot acquired
+ * Modem has registered
+ * HDR Revision: A
+ *
+ * Unregistered AC580:
+ * -----------------------
+ * Current band: PCS CDMA
+ * Current channel: 350
+ * SID: 0 NID: 0 Roaming: 0
+ * Temp: 39 State: 100 Scan Mode: 0
+ * Pilot NOT acquired
+ * Modem has NOT registered
+ *
+ * Registered AC580:
+ * -----------------------
+ * Current band: Cellular Sleep
+ * Current channel: 548
+ * SID: 26 NID: 1 Roaming: 1
+ * Temp: 39 State: 200 Scan Mode: 0
+ * Pilot Acquired
+ * Modem has registered
+ */
+
+ /* We have to handle the two formats slightly differently; for newer formats
+ * with "Sys Mode", we consider the modem registered if the Sys Mode is not
+ * "NO SRV". The explicit registration status is just icing on the cake.
+ * For older formats (no "Sys Mode") we treat the modem as registered if
+ * the SID is non-zero.
+ */
+
+ for (iter = lines; iter && *iter; iter++) {
+ gboolean bool_val = FALSE;
+ char *p;
+
+ if (!strncmp (*iter, MODEM_REG_TAG, strlen (MODEM_REG_TAG))) {
+ registered = TRUE;
+ continue;
+ }
+
+ /* 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;
+ }
+
+ /* Current system mode */
+ p = strstr (*iter, SYS_MODE_TAG);
+ if (p) {
+ p += strlen (SYS_MODE_TAG);
+ while (*p && isspace (*p))
+ p++;
+ if (!strncmp (p, SYS_MODE_NO_SERVICE_TAG, strlen (SYS_MODE_NO_SERVICE_TAG)))
+ 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)))
+ sys_mode = SYS_MODE_CDMA_1X;
+ }
+
+ /* Current EVDO revision if system mode is EVDO */
+ p = strstr (*iter, EVDO_REV_TAG);
+ if (p) {
+ p += strlen (EVDO_REV_TAG);
+ while (*p && isspace (*p))
+ p++;
+ if (*p == 'A')
+ evdo_mode = SYS_MODE_EVDO_REVA;
+ else if (*p == '0')
+ evdo_mode = SYS_MODE_EVDO_REV0;
+ }
+
+ /* SID */
+ p = strstr (*iter, SID_TAG);
+ if (p) {
+ p += strlen (SID_TAG);
+ while (*p && isspace (*p))
+ p++;
+ if (isdigit (*p) && (*p != '0'))
+ have_sid = TRUE;
+ }
+ }
+
+ /* Update current system mode */
+ if (sys_mode == SYS_MODE_EVDO_REV0 || sys_mode == SYS_MODE_EVDO_REVA) {
+ /* 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);
+ } else {
+ /* Not registered */
+ mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
+ mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
+ }
+
+done:
+ mm_callback_info_schedule (info);
+}
+
+static void
+query_registration_state (MMGenericCdma *cdma,
+ 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);
+
+ 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;
+ }
+
+ /* Use secondary port if primary is connected */
+ port = secondary;
+ }
+
+ mm_serial_port_queue_command (port, "!STATUS", 3, status_done, info);
+}
+
+static void
+pcstate_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ /* Ignore errors for now; we're not sure if all Sierra CDMA devices support
+ * at!pcstate.
+ */
+ mm_callback_info_schedule ((MMCallbackInfo *) user_data);
+}
+
+static void
+post_enable (MMGenericCdma *cdma,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMSerialPort *primary;
+
+ info = mm_callback_info_new (MM_MODEM (cdma), callback, user_data);
+
+ primary = mm_generic_cdma_get_port (cdma, MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
+ mm_serial_port_queue_command (primary, "!pcstate=1", 5, pcstate_done, info);
+}
+
+static void
+post_disable (MMGenericCdma *cdma,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMSerialPort *primary;
+
+ info = mm_callback_info_new (MM_MODEM (cdma), callback, user_data);
+
+ primary = mm_generic_cdma_get_port (cdma, MM_PORT_TYPE_PRIMARY);
+ g_assert (primary);
+
+ mm_serial_port_queue_command (primary, "!pcstate=0", 5, pcstate_done, info);
+}
+
+/*****************************************************************************/
+
+static void
+mm_modem_sierra_cdma_init (MMModemSierraCdma *self)
+{
+}
+
+static void
+mm_modem_sierra_cdma_class_init (MMModemSierraCdmaClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMGenericCdmaClass *cdma_class = MM_GENERIC_CDMA_CLASS (klass);
+
+ mm_modem_sierra_cdma_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (object_class, sizeof (MMModemSierraCdmaPrivate));
+
+ cdma_class->query_registration_state = query_registration_state;
+ cdma_class->post_enable = post_enable;
+ cdma_class->post_disable = post_disable;
+}
+
diff --git a/plugins/mm-modem-sierra-cdma.h b/plugins/mm-modem-sierra-cdma.h
new file mode 100644
index 0000000..9111b73
--- /dev/null
+++ b/plugins/mm-modem-sierra-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 Red Hat, Inc.
+ */
+
+#ifndef MM_MODEM_SIERRA_CDMA_H
+#define MM_MODEM_SIERRA_CDMA_H
+
+#include "mm-generic-cdma.h"
+
+#define MM_TYPE_MODEM_SIERRA_CDMA (mm_modem_sierra_cdma_get_type ())
+#define MM_MODEM_SIERRA_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_SIERRA_CDMA, MMModemSierraCdma))
+#define MM_MODEM_SIERRA_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_SIERRA_CDMA, MMModemSierraCdmaClass))
+#define MM_IS_MODEM_SIERRA_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_SIERRA_CDMA))
+#define MM_IS_MODEM_SIERRA_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_SIERRA_CDMA))
+#define MM_MODEM_SIERRA_CDMA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_SIERRA_CDMA, MMModemSierraCdmaClass))
+
+typedef struct {
+ MMGenericCdma parent;
+} MMModemSierraCdma;
+
+typedef struct {
+ MMGenericCdmaClass parent;
+} MMModemSierraCdmaClass;
+
+GType mm_modem_sierra_cdma_get_type (void);
+
+MMModem *mm_modem_sierra_cdma_new (const char *device,
+ const char *driver,
+ const char *plugin,
+ gboolean evdo_rev0,
+ gboolean evdo_revA);
+
+#endif /* MM_MODEM_SIERRA_CDMA_H */
diff --git a/plugins/mm-modem-sierra-gsm.c b/plugins/mm-modem-sierra-gsm.c
new file mode 100644
index 0000000..ee82234
--- /dev/null
+++ b/plugins/mm-modem-sierra-gsm.c
@@ -0,0 +1,145 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "mm-modem-sierra-gsm.h"
+#include "mm-errors.h"
+#include "mm-callback-info.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))
+
+
+MMModem *
+mm_modem_sierra_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_SIERRA_GSM,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ NULL));
+}
+
+/*****************************************************************************/
+/* Modem class override functions */
+/*****************************************************************************/
+
+static void
+pin_check_done (MMModem *modem, GError *error, gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info);
+}
+
+static gboolean
+sierra_enabled (gpointer data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) data;
+
+ /* 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;
+}
+
+static void
+parent_enable_done (MMModem *modem, GError *error, gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ if (error) {
+ mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, 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);
+}
+
+static void
+enable (MMModem *modem, MMModemFn callback, gpointer user_data)
+{
+ MMModem *parent_modem_iface;
+ 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);
+}
+
+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_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;
+
+ 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);
+
+ return !!port;
+}
+
+/*****************************************************************************/
+
+static void
+modem_init (MMModem *modem_class)
+{
+ modem_class->enable = enable;
+ modem_class->grab_port = grab_port;
+}
+
+static void
+mm_modem_sierra_gsm_init (MMModemSierraGsm *self)
+{
+}
+
+static void
+mm_modem_sierra_gsm_class_init (MMModemSierraGsmClass *klass)
+{
+ mm_modem_sierra_gsm_parent_class = g_type_class_peek_parent (klass);
+}
+
diff --git a/plugins/mm-modem-sierra-gsm.h b/plugins/mm-modem-sierra-gsm.h
new file mode 100644
index 0000000..dd84b30
--- /dev/null
+++ b/plugins/mm-modem-sierra-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_SIERRA_GSM_H
+#define MM_MODEM_SIERRA_GSM_H
+
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_SIERRA_GSM (mm_modem_sierra_gsm_get_type ())
+#define MM_MODEM_SIERRA_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_SIERRA_GSM, MMModemSierraGsm))
+#define MM_MODEM_SIERRA_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_SIERRA_GSM, MMModemSierraGsmClass))
+#define MM_IS_MODEM_SIERRA_GSM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_SIERRA_GSM))
+#define MM_IS_MODEM_SIERRA_GSM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_SIERRA_GSM))
+#define MM_MODEM_SIERRA_GSM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_SIERRA_GSM, MMModemSierraGsmClass))
+
+typedef struct {
+ MMGenericGsm parent;
+} MMModemSierraGsm;
+
+typedef struct {
+ MMGenericGsmClass parent;
+} MMModemSierraGsmClass;
+
+GType mm_modem_sierra_gsm_get_type (void);
+
+MMModem *mm_modem_sierra_gsm_new (const char *device,
+ const char *driver,
+ const char *plugin_name);
+
+#endif /* MM_MODEM_SIERRA_GSM_H */
diff --git a/plugins/mm-modem-zte.c b/plugins/mm-modem-zte.c
new file mode 100644
index 0000000..92c23ae
--- /dev/null
+++ b/plugins/mm-modem-zte.c
@@ -0,0 +1,235 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "mm-modem-zte.h"
+#include "mm-serial-port.h"
+#include "mm-errors.h"
+#include "mm-callback-info.h"
+
+static void modem_init (MMModem *modem_class);
+
+G_DEFINE_TYPE_EXTENDED (MMModemZte, mm_modem_zte, MM_TYPE_GENERIC_GSM, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init))
+
+#define MM_MODEM_ZTE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_ZTE, MMModemZtePrivate))
+
+typedef struct {
+ gboolean init_retried;
+} MMModemZtePrivate;
+
+MMModem *
+mm_modem_zte_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_ZTE,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ NULL));
+}
+
+/*****************************************************************************/
+/* Modem class override functions */
+/*****************************************************************************/
+
+static void
+init_modem_done (MMSerialPort *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);
+}
+
+static void
+pin_check_done (MMModem *modem, 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);
+ 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);
+}
+
+static void enable_flash_done (MMSerialPort *port,
+ GError *error,
+ gpointer user_data);
+
+static void
+pre_init_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (info->modem);
+
+ 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)) {
+ priv->init_retried = TRUE;
+ enable_flash_done (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);
+ }
+}
+
+static void
+enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) 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);
+}
+
+static void
+do_enable (MMGenericGsm *modem, MMModemFn callback, gpointer user_data)
+{
+ MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (modem);
+ MMCallbackInfo *info;
+ MMSerialPort *primary;
+
+ priv->init_retried = FALSE;
+
+ primary = mm_generic_gsm_get_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);
+}
+
+static void
+disable (MMModem *modem,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (modem);
+ MMModem *parent_modem_iface;
+
+ priv->init_retried = FALSE;
+
+ /* Do the normal disable stuff */
+ parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem));
+ parent_modem_iface->disable (modem, callback, user_data);
+}
+
+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_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;
+
+ port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
+ if (port && MM_IS_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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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_zte_init (MMModemZte *self)
+{
+}
+
+static void
+mm_modem_zte_class_init (MMModemZteClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
+
+ mm_modem_zte_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (object_class, sizeof (MMModemZtePrivate));
+
+ gsm_class->do_enable = do_enable;
+}
+
diff --git a/plugins/mm-modem-zte.h b/plugins/mm-modem-zte.h
new file mode 100644
index 0000000..112bae0
--- /dev/null
+++ b/plugins/mm-modem-zte.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_ZTE_H
+#define MM_MODEM_ZTE_H
+
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_MODEM_ZTE (mm_modem_zte_get_type ())
+#define MM_MODEM_ZTE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_ZTE, MMModemZte))
+#define MM_MODEM_ZTE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_ZTE, MMModemZteClass))
+#define MM_IS_MODEM_ZTE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_ZTE))
+#define MM_IS_MODEM_ZTE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_ZTE))
+#define MM_MODEM_ZTE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_ZTE, MMModemZteClass))
+
+typedef struct {
+ MMGenericGsm parent;
+} MMModemZte;
+
+typedef struct {
+ MMGenericGsmClass parent;
+} MMModemZteClass;
+
+GType mm_modem_zte_get_type (void);
+
+MMModem *mm_modem_zte_new (const char *device,
+ const char *driver,
+ const char *plugin);
+
+#endif /* MM_MODEM_ZTE_H */
diff --git a/plugins/mm-plugin-anydata.c b/plugins/mm-plugin-anydata.c
new file mode 100644
index 0000000..e451714
--- /dev/null
+++ b/plugins/mm-plugin-anydata.c
@@ -0,0 +1,179 @@
+/* -*- 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-anydata.h"
+#include "mm-modem-anydata-cdma.h"
+
+G_DEFINE_TYPE (MMPluginAnydata, mm_plugin_anydata, 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_ANYDATA,
+ MM_PLUGIN_BASE_NAME, "AnyData",
+ 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)
+{
+ /* Only CDMA for now */
+ if (capabilities & CAP_CDMA)
+ return 10;
+
+ return 0;
+}
+
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
+{
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
+}
+
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
+{
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *subsys, *name;
+ guint16 vendor = 0;
+
+ /* Can't do anything with non-serial ports */
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (vendor != 0x16d5)
+ 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, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
+ guint32 caps;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ devfile = g_udev_device_get_device_file (port);
+ if (!devfile) {
+ g_set_error (error, 0, 0, "Could not get port's sysfs file.");
+ return NULL;
+ }
+
+ 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);
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ g_set_error (error, 0, 0, "Only CDMA modems are currently supported by this plugin.");
+ return NULL;
+ }
+
+ if (!existing) {
+ if (caps & CAP_CDMA) {
+ modem = mm_modem_anydata_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, MM_PORT_TYPE_UNKNOWN, NULL, error)) {
+ g_object_unref (modem);
+ 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;
+ }
+ }
+
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_anydata_init (MMPluginAnydata *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_anydata_class_init (MMPluginAnydataClass *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-anydata.h b/plugins/mm-plugin-anydata.h
new file mode 100644
index 0000000..b71aad3
--- /dev/null
+++ b/plugins/mm-plugin-anydata.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_ANYDATA_H
+#define MM_PLUGIN_ANYDATA_H
+
+#include "mm-plugin-base.h"
+
+#define MM_TYPE_PLUGIN_ANYDATA (mm_plugin_anydata_get_type ())
+#define MM_PLUGIN_ANYDATA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_ANYDATA, MMPluginAnydata))
+#define MM_PLUGIN_ANYDATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_ANYDATA, MMPluginAnydataClass))
+#define MM_IS_PLUGIN_ANYDATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_ANYDATA))
+#define MM_IS_PLUGIN_ANYDATA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_ANYDATA))
+#define MM_PLUGIN_ANYDATA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_ANYDATA, MMPluginAnydataClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginAnydata;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginAnydataClass;
+
+GType mm_plugin_anydata_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_ANYDATA_H */
diff --git a/plugins/mm-plugin-generic.c b/plugins/mm-plugin-generic.c
new file mode 100644
index 0000000..e5e2ade
--- /dev/null
+++ b/plugins/mm-plugin-generic.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 Dan Williams <dcbw@redhat.com>
+ */
+
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <time.h>
+
+#include <gmodule.h>
+
+#include "mm-plugin-generic.h"
+#include "mm-generic-gsm.h"
+#include "mm-generic-cdma.h"
+#include "mm-errors.h"
+#include "mm-serial-parsers.h"
+
+G_DEFINE_TYPE (MMPluginGeneric, mm_plugin_generic, 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_GENERIC,
+ MM_PLUGIN_BASE_NAME, MM_PLUGIN_GENERIC_NAME,
+ 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 5;
+ if (capabilities & CAP_CDMA)
+ return 5;
+ 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;
+
+ /* 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;
+
+ 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, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path, *driver;
+ guint32 caps;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ devfile = g_udev_device_get_device_file (port);
+ if (!devfile) {
+ driver = mm_plugin_base_supports_task_get_driver (task);
+ if (!driver || strcmp (driver, "bluetooth")) {
+ g_set_error (error, 0, 0, "Could not get port's sysfs file.");
+ return NULL;
+ } else {
+ g_message ("%s: (%s/%s) WARNING: missing udev 'device' file",
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ subsys,
+ name);
+ }
+ }
+
+ 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);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_generic_gsm_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ } else if (caps & CAP_CDMA) {
+ 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, MM_PORT_TYPE_UNKNOWN, NULL, error)) {
+ g_object_unref (modem);
+ 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;
+ }
+ }
+
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_generic_init (MMPluginGeneric *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_generic_class_init (MMPluginGenericClass *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-generic.h b/plugins/mm-plugin-generic.h
new file mode 100644
index 0000000..8d05689
--- /dev/null
+++ b/plugins/mm-plugin-generic.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) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_PLUGIN_GENERIC_H
+#define MM_PLUGIN_GENERIC_H
+
+#include "mm-plugin.h"
+#include "mm-plugin-base.h"
+
+#define MM_TYPE_PLUGIN_GENERIC (mm_plugin_generic_get_type ())
+#define MM_PLUGIN_GENERIC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_GENERIC, MMPluginGeneric))
+#define MM_PLUGIN_GENERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_GENERIC, MMPluginGenericClass))
+#define MM_IS_PLUGIN_GENERIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_GENERIC))
+#define MM_IS_PLUGIN_GENERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_GENERIC))
+#define MM_PLUGIN_GENERIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_GENERIC, MMPluginGenericClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginGeneric;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginGenericClass;
+
+GType mm_plugin_generic_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_GENERIC_H */
diff --git a/plugins/mm-plugin-gobi.c b/plugins/mm-plugin-gobi.c
new file mode 100644
index 0000000..77da965
--- /dev/null
+++ b/plugins/mm-plugin-gobi.c
@@ -0,0 +1,171 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <gmodule.h>
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+
+#include "mm-plugin-gobi.h"
+#include "mm-modem-gobi-gsm.h"
+#include "mm-generic-cdma.h"
+
+G_DEFINE_TYPE (MMPluginGobi, mm_plugin_gobi, 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_GOBI,
+ MM_PLUGIN_BASE_NAME, "Gobi",
+ 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;
+ return 0;
+}
+
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
+{
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
+}
+
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
+{
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *driver;
+
+ /* 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;
+
+ driver = mm_plugin_base_supports_task_get_driver (task);
+ if (!driver || strcmp (driver, "qcserial"))
+ 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, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *sysfs_path;
+ guint32 caps;
+
+ 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);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_modem_gobi_gsm_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ } 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, MM_PORT_TYPE_UNKNOWN, NULL, error)) {
+ g_object_unref (modem);
+ 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;
+ }
+ }
+
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_gobi_init (MMPluginGobi *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_gobi_class_init (MMPluginGobiClass *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-gobi.h b/plugins/mm-plugin-gobi.h
new file mode 100644
index 0000000..aceba6b
--- /dev/null
+++ b/plugins/mm-plugin-gobi.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_PLUGIN_GOBI_H
+#define MM_PLUGIN_GOBI_H
+
+#include "mm-plugin.h"
+#include "mm-plugin-base.h"
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_PLUGIN_GOBI (mm_plugin_gobi_get_type ())
+#define MM_PLUGIN_GOBI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_GOBI, MMPluginGobi))
+#define MM_PLUGIN_GOBI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_GOBI, MMPluginGobiClass))
+#define MM_IS_PLUGIN_GOBI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_GOBI))
+#define MM_IS_PLUGIN_GOBI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_GOBI))
+#define MM_PLUGIN_GOBI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_GOBI, MMPluginGobiClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginGobi;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginGobiClass;
+
+GType mm_plugin_gobi_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_GOBI_H */
+
diff --git a/plugins/mm-plugin-hso.c b/plugins/mm-plugin-hso.c
new file mode 100644
index 0000000..8493c9c
--- /dev/null
+++ b/plugins/mm-plugin-hso.c
@@ -0,0 +1,182 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <gmodule.h>
+
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+
+#include "mm-plugin-hso.h"
+#include "mm-modem-hso.h"
+
+G_DEFINE_TYPE (MMPluginHso, mm_plugin_hso, 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_HSO,
+ MM_PLUGIN_BASE_NAME, "Option High-Speed",
+ NULL));
+}
+
+/*****************************************************************************/
+
+static guint32
+get_level_for_capabilities (guint32 capabilities)
+{
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 10;
+ return 0;
+}
+
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
+{
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
+}
+
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
+{
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *driver, *subsys;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+
+ driver = mm_plugin_base_supports_task_get_driver (task);
+ if (!driver || strcmp (driver, "hso"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ subsys = g_udev_device_get_subsystem (port);
+ g_assert (subsys);
+ if (!strcmp (subsys, "net")) {
+ mm_plugin_base_supports_task_complete (task, 10);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
+
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
+ 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, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *sysfs_path;
+ char *devfile;
+ guint32 caps;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ devfile = g_strdup (g_udev_device_get_device_file (port));
+ if (!devfile) {
+ if (!strcmp (subsys, "net")) {
+ /* Apparently 'hso' doesn't set up the right links for the netdevice,
+ * and thus libgudev can't get the sysfs file path for it.
+ */
+ devfile = g_strdup_printf ("/sys/class/net/%s", name);
+ if (!g_file_test (devfile, G_FILE_TEST_EXISTS)) {
+ g_free (devfile);
+ devfile = NULL;
+ }
+ }
+
+ if (!devfile) {
+ g_set_error (error, 0, 0, "Could not get port's sysfs file.");
+ goto out;
+ }
+ }
+
+ 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;
+
+ if (!existing) {
+ modem = mm_modem_hso_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ if (modem) {
+ if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error)) {
+ g_object_unref (modem);
+ return NULL;
+ }
+ }
+ } else {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error))
+ return NULL;
+ }
+
+out:
+ g_free (devfile);
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_hso_init (MMPluginHso *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_hso_class_init (MMPluginHsoClass *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-hso.h b/plugins/mm-plugin-hso.h
new file mode 100644
index 0000000..a3f4caf
--- /dev/null
+++ b/plugins/mm-plugin-hso.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_PLUGIN_HSO_H
+#define MM_PLUGIN_HSO_H
+
+#include "mm-plugin.h"
+#include "mm-plugin-base.h"
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_PLUGIN_HSO (mm_plugin_hso_get_type ())
+#define MM_PLUGIN_HSO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_HSO, MMPluginHso))
+#define MM_PLUGIN_HSO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_HSO, MMPluginHsoClass))
+#define MM_IS_PLUGIN_HSO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_HSO))
+#define MM_IS_PLUGIN_HSO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_HSO))
+#define MM_PLUGIN_HSO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_HSO, MMPluginHsoClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginHso;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginHsoClass;
+
+GType mm_plugin_hso_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_HSO_H */
diff --git a/plugins/mm-plugin-huawei.c b/plugins/mm-plugin-huawei.c
new file mode 100644
index 0000000..ad799f0
--- /dev/null
+++ b/plugins/mm-plugin-huawei.c
@@ -0,0 +1,341 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <gmodule.h>
+
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+
+#include "mm-plugin-huawei.h"
+#include "mm-generic-gsm.h"
+#include "mm-generic-cdma.h"
+#include "mm-modem-huawei-gsm.h"
+#include "mm-modem-huawei-cdma.h"
+#include "mm-serial-parsers.h"
+
+G_DEFINE_TYPE (MMPluginHuawei, mm_plugin_huawei, 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_HUAWEI,
+ MM_PLUGIN_BASE_NAME, "Huawei",
+ 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;
+ 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));
+}
+
+#define TAG_SUPPORTS_INFO "huawei-supports-info"
+
+typedef struct {
+ MMSerialPort *serial;
+ guint id;
+ gboolean secondary;
+} HuaweiSupportsInfo;
+
+static void
+huawei_supports_info_destroy (gpointer user_data)
+{
+ HuaweiSupportsInfo *info = user_data;
+
+ if (info->id)
+ g_source_remove (info->id);
+ if (info->serial)
+ g_object_unref (info->serial);
+ memset (info, 0, sizeof (HuaweiSupportsInfo));
+ g_free (info);
+}
+
+static gboolean
+probe_secondary_supported (gpointer user_data)
+{
+ MMPluginBaseSupportsTask *task = user_data;
+ HuaweiSupportsInfo *info;
+
+ info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO);
+
+ info->id = 0;
+ g_object_unref (info->serial);
+ info->serial = NULL;
+
+ /* Yay, supported, we got an unsolicited message */
+ info->secondary = TRUE;
+ mm_plugin_base_supports_task_complete (task, 10);
+ return FALSE;
+}
+
+static void
+probe_secondary_handle_msg (MMSerialPort *port,
+ GMatchInfo *match_info,
+ gpointer user_data)
+{
+ MMPluginBaseSupportsTask *task = user_data;
+ HuaweiSupportsInfo *info;
+
+ info = g_object_get_data (G_OBJECT (task), TAG_SUPPORTS_INFO);
+ g_source_remove (info->id);
+ info->id = g_idle_add (probe_secondary_supported, task);
+}
+
+static gboolean
+probe_secondary_timeout (gpointer user_data)
+{
+ MMPluginBaseSupportsTask *task = user_data;
+ HuaweiSupportsInfo *info;
+
+ 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);
+ return FALSE;
+}
+
+static void
+add_regex (MMSerialPort *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);
+ g_regex_unref (regex);
+}
+
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
+{
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *subsys, *name;
+ int usbif;
+ guint16 vendor = 0, product = 0;
+ guint32 existing_type = MM_MODEM_TYPE_UNKNOWN;
+
+ /* 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, &product))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (vendor != 0x12d1)
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ usbif = g_udev_device_get_property_as_int (port, "ID_USB_INTERFACE_NUM");
+ if (usbif < 0)
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ /* The secondary ports don't necessarily respond correctly to probing, so
+ * we need to use the first port that does respond to probing to create the
+ * right type of mode (GSM or CDMA), and then re-check the other interfaces.
+ */
+ if (!existing && usbif != 0)
+ return MM_PLUGIN_SUPPORTS_PORT_DEFER;
+
+ /* CDMA devices don't have problems with the secondary ports, so after
+ * ensuring we have a device by probing the first port, probe the secondary
+ * ports on CDMA devices too.
+ */
+ if (existing)
+ g_object_get (G_OBJECT (existing), MM_MODEM_TYPE, &existing_type, NULL);
+
+ if (usbif == 0 || (existing_type == MM_MODEM_TYPE_CDMA)) {
+ 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;
+ } else {
+ HuaweiSupportsInfo *info;
+ GError *error = NULL;
+
+ /* Listen for Huawei-specific unsolicited messages */
+ info = g_malloc0 (sizeof (HuaweiSupportsInfo));
+
+ info->serial = mm_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);
+
+ add_regex (info->serial, "\\r\\n\\^RSSI:(\\d+)\\r\\n", task);
+ add_regex (info->serial, "\\r\\n\\^MODE:(\\d),(\\d)\\r\\n", task);
+ add_regex (info->serial, "\\r\\n\\^DSFLOWRPT:(.+)\\r\\n", task);
+ 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);
+
+ g_object_set_data_full (G_OBJECT (task), TAG_SUPPORTS_INFO,
+ info, huawei_supports_info_destroy);
+
+ if (!mm_serial_port_open (info->serial, &error)) {
+ g_warning ("%s: (Huawei) %s: couldn't open serial port: (%d) %s",
+ __func__, name,
+ error ? error->code : -1,
+ error && error->message ? error->message : "(unknown)");
+ g_clear_error (&error);
+ huawei_supports_info_destroy (info);
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+ }
+
+ 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, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
+ guint32 caps;
+ guint16 product = 0;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ devfile = g_udev_device_get_device_file (port);
+ if (!devfile) {
+ g_set_error (error, 0, 0, "Could not get port's sysfs file.");
+ return NULL;
+ }
+
+ 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);
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, NULL, &product)) {
+ g_set_error (error, 0, 0, "Could not get modem product ID.");
+ return NULL;
+ }
+
+ caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
+ 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)));
+ }
+ } else if (caps & CAP_CDMA) {
+ modem = mm_modem_huawei_cdma_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856),
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A));
+ }
+
+ if (modem) {
+ if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error)) {
+ g_object_unref (modem);
+ return NULL;
+ }
+ }
+ } else {
+ HuaweiSupportsInfo *info;
+ 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;
+
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error))
+ return NULL;
+ }
+
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_huawei_init (MMPluginHuawei *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_huawei_class_init (MMPluginHuaweiClass *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-huawei.h b/plugins/mm-plugin-huawei.h
new file mode 100644
index 0000000..de9294c
--- /dev/null
+++ b/plugins/mm-plugin-huawei.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_PLUGIN_HUAWEI_H
+#define MM_PLUGIN_HUAWEI_H
+
+#include "mm-plugin.h"
+#include "mm-plugin-base.h"
+
+#define MM_TYPE_PLUGIN_HUAWEI (mm_plugin_huawei_get_type ())
+#define MM_PLUGIN_HUAWEI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_HUAWEI, MMPluginHuawei))
+#define MM_PLUGIN_HUAWEI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_HUAWEI, MMPluginHuaweiClass))
+#define MM_IS_PLUGIN_HUAWEI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_HUAWEI))
+#define MM_IS_PLUGIN_HUAWEI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_HUAWEI))
+#define MM_PLUGIN_HUAWEI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_HUAWEI, MMPluginHuaweiClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginHuawei;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginHuaweiClass;
+
+GType mm_plugin_huawei_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_HUAWEI_H */
diff --git a/plugins/mm-plugin-longcheer.c b/plugins/mm-plugin-longcheer.c
new file mode 100644
index 0000000..5c19b13
--- /dev/null
+++ b/plugins/mm-plugin-longcheer.c
@@ -0,0 +1,191 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <gmodule.h>
+#include "mm-plugin-longcheer.h"
+#include "mm-generic-gsm.h"
+#include "mm-generic-cdma.h"
+
+G_DEFINE_TYPE (MMPluginLongcheer, mm_plugin_longcheer, 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_LONGCHEER,
+ MM_PLUGIN_BASE_NAME, "Longcheer",
+ 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;
+ 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;
+
+ if (vendor != 0x1c9e)
+ 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, *physdev = 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_LONGCHEER_PORT_TYPE_MODEM"))
+ ptype = MM_PORT_TYPE_PRIMARY;
+ else if (g_udev_device_get_property_as_boolean (port, "ID_MM_LONGCHEER_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_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);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_generic_gsm_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ } else if (caps & CAP_CDMA) {
+ 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 (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error))
+ return NULL;
+ }
+ }
+
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_longcheer_init (MMPluginLongcheer *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_longcheer_class_init (MMPluginLongcheerClass *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-longcheer.h b/plugins/mm-plugin-longcheer.h
new file mode 100644
index 0000000..387a290
--- /dev/null
+++ b/plugins/mm-plugin-longcheer.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_PLUGIN_LONGCHEER_H
+#define MM_PLUGIN_LONGCHEER_H
+
+#include "mm-plugin-base.h"
+
+#define MM_TYPE_PLUGIN_LONGCHEER (mm_plugin_longcheer_get_type ())
+#define MM_PLUGIN_LONGCHEER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_LONGCHEER, MMPluginLongcheer))
+#define MM_PLUGIN_LONGCHEER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_LONGCHEER, MMPluginLongcheerClass))
+#define MM_IS_PLUGIN_LONGCHEER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_LONGCHEER))
+#define MM_IS_PLUGIN_LONGCHEER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_LONGCHEER))
+#define MM_PLUGIN_LONGCHEER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_LONGCHEER, MMPluginLongcheerClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginLongcheer;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginLongcheerClass;
+
+GType mm_plugin_longcheer_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_LONGCHEER_H */
diff --git a/plugins/mm-plugin-mbm.c b/plugins/mm-plugin-mbm.c
new file mode 100644
index 0000000..a380f98
--- /dev/null
+++ b/plugins/mm-plugin-mbm.c
@@ -0,0 +1,175 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2008 Ericsson AB
+ *
+ * Author: Per Hallsmark <per.hallsmark@ericsson.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
+ * 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.
+ *
+ * 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>
+#include <gmodule.h>
+
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+
+#include "mm-plugin-mbm.h"
+#include "mm-modem-mbm.h"
+
+G_DEFINE_TYPE (MMPluginMbm, mm_plugin_mbm, 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_MBM,
+ MM_PLUGIN_BASE_NAME, "Ericsson MBM",
+ NULL));
+}
+
+/*****************************************************************************/
+
+static guint32
+get_level_for_capabilities (guint32 capabilities)
+{
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 10;
+ return 0;
+}
+
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
+{
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
+}
+
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
+{
+ GUdevDevice *port, *physdev;
+ guint32 cached = 0, level;
+ const char *driver, *subsys;
+
+ /* Can't do anything with non-serial ports */
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+ subsys = g_udev_device_get_subsystem (port);
+ g_assert (subsys);
+
+ if (strcmp (subsys, "tty") && strcmp (subsys, "net"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ driver = mm_plugin_base_supports_task_get_driver (task);
+ if (!driver)
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ physdev = mm_plugin_base_supports_task_get_physdev (task);
+ g_assert (physdev);
+ if (!g_udev_device_get_property_as_boolean (physdev, "ID_MM_ERICSSON_MBM"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (!strcmp (subsys, "net")) {
+ mm_plugin_base_supports_task_complete (task, 10);
+ return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS;
+ }
+
+ if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) {
+ level = get_level_for_capabilities (cached);
+ if (level) {
+ 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, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *sysfs_path;
+ guint32 caps;
+
+ 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);
+ if (!(caps & MM_PLUGIN_BASE_PORT_CAP_GSM) && strcmp (subsys, "net"))
+ return NULL;
+
+ if (!existing) {
+ modem = mm_modem_mbm_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ if (modem) {
+ if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error)) {
+ g_object_unref (modem);
+ return NULL;
+ }
+ }
+ } else {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error))
+ return NULL;
+ }
+
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_mbm_init (MMPluginMbm *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_mbm_class_init (MMPluginMbmClass *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-mbm.h b/plugins/mm-plugin-mbm.h
new file mode 100644
index 0000000..c0e73b5
--- /dev/null
+++ b/plugins/mm-plugin-mbm.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2008 Ericsson AB
+ *
+ * Author: Per Hallsmark <per.hallsmark@ericsson.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
+ * 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.
+ *
+ * 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
+#define MM_PLUGIN_MBM_H
+
+#include "mm-plugin-base.h"
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_PLUGIN_MBM (mm_plugin_mbm_get_type ())
+#define MM_PLUGIN_MBM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_MBM, MMPluginMbm))
+#define MM_PLUGIN_MBM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_MBM, MMPluginMbmClass))
+#define MM_IS_PLUGIN_MBM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_MBM))
+#define MM_IS_PLUGIN_MBM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_MBM))
+#define MM_PLUGIN_MBM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_MBM, MMPluginMbmClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginMbm;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginMbmClass;
+
+GType mm_plugin_mbm_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_MBM_H */
diff --git a/plugins/mm-plugin-moto-c.c b/plugins/mm-plugin-moto-c.c
new file mode 100644
index 0000000..5b32a1e
--- /dev/null
+++ b/plugins/mm-plugin-moto-c.c
@@ -0,0 +1,160 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <gmodule.h>
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+
+#include "mm-plugin-moto-c.h"
+#include "mm-modem-moto-c-gsm.h"
+
+G_DEFINE_TYPE (MMPluginMotoC, mm_plugin_moto_c, 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_MOTO_C,
+ MM_PLUGIN_BASE_NAME, "MotoC",
+ NULL));
+}
+
+/*****************************************************************************/
+
+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);
+}
+
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
+{
+ GUdevDevice *port;
+ const char *tmp;
+ guint32 cached = 0;
+
+ /* Can't do anything with non-serial ports */
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ tmp = g_udev_device_get_property (port, "ID_BUS");
+ if (!tmp || strcmp (tmp, "usb"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ tmp = g_udev_device_get_property (port, "ID_VENDOR_ID");
+ if (!tmp || strcmp (tmp, "22b8"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ tmp = g_udev_device_get_property (port, "ID_MODEL_ID");
+ if (!tmp || (strcmp (tmp, "3802") && strcmp (tmp, "4902")))
+ 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) {
+ mm_plugin_base_supports_task_complete (task, 10);
+ 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, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ devfile = g_udev_device_get_device_file (port);
+ if (!devfile) {
+ g_set_error (error, 0, 0, "Could not get port's sysfs file.");
+ return NULL;
+ }
+
+ 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);
+
+ if (!existing) {
+ modem = mm_modem_moto_c_gsm_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+
+ if (modem) {
+ if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error)) {
+ g_object_unref (modem);
+ return NULL;
+ }
+ }
+ } else {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error))
+ return NULL;
+ }
+
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_moto_c_init (MMPluginMotoC *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_moto_c_class_init (MMPluginMotoCClass *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-moto-c.h b/plugins/mm-plugin-moto-c.h
new file mode 100644
index 0000000..8583607
--- /dev/null
+++ b/plugins/mm-plugin-moto-c.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_PLUGIN_MOTO_C_H
+#define MM_PLUGIN_MOTO_C_H
+
+#include "mm-plugin.h"
+#include "mm-plugin-base.h"
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_PLUGIN_MOTO_C (mm_plugin_moto_c_get_type ())
+#define MM_PLUGIN_MOTO_C(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_MOTO_C, MMPluginMotoC))
+#define MM_PLUGIN_MOTO_C_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_MOTO_C, MMPluginMotoCClass))
+#define MM_IS_PLUGIN_MOTO_C(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_MOTO_C))
+#define MM_IS_PLUGIN_MOTO_C_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_MOTO_C))
+#define MM_PLUGIN_MOTO_C_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_MOTO_C, MMPluginMotoCClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginMotoC;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginMotoCClass;
+
+GType mm_plugin_moto_c_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_MOTO_C_H */
diff --git a/plugins/mm-plugin-nokia.c b/plugins/mm-plugin-nokia.c
new file mode 100644
index 0000000..e088323
--- /dev/null
+++ b/plugins/mm-plugin-nokia.c
@@ -0,0 +1,179 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <gmodule.h>
+#include "mm-plugin-nokia.h"
+#include "mm-modem-nokia.h"
+#include "mm-generic-cdma.h"
+
+G_DEFINE_TYPE (MMPluginNokia, mm_plugin_nokia, 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_NOKIA,
+ MM_PLUGIN_BASE_NAME, "Nokia",
+ 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;
+ return 0;
+}
+
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
+{
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
+}
+
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
+{
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *subsys, *name;
+ guint16 vendor = 0;
+
+ /* Can't do anything with non-serial ports */
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (vendor != 0x0421)
+ 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, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
+ guint32 caps;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ devfile = g_udev_device_get_device_file (port);
+ if (!devfile) {
+ g_set_error (error, 0, 0, "Could not get port's sysfs file.");
+ return NULL;
+ }
+
+ 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);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_modem_nokia_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ } 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, MM_PORT_TYPE_UNKNOWN, NULL, error)) {
+ g_object_unref (modem);
+ 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;
+ }
+ }
+
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_nokia_init (MMPluginNokia *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_nokia_class_init (MMPluginNokiaClass *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-nokia.h b/plugins/mm-plugin-nokia.h
new file mode 100644
index 0000000..fdc0f41
--- /dev/null
+++ b/plugins/mm-plugin-nokia.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_PLUGIN_NOKIA_H
+#define MM_PLUGIN_NOKIA_H
+
+#include "mm-plugin-base.h"
+
+#define MM_TYPE_PLUGIN_NOKIA (mm_plugin_nokia_get_type ())
+#define MM_PLUGIN_NOKIA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_NOKIA, MMPluginNokia))
+#define MM_PLUGIN_NOKIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_NOKIA, MMPluginNokiaClass))
+#define MM_IS_PLUGIN_NOKIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_NOKIA))
+#define MM_IS_PLUGIN_NOKIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_NOKIA))
+#define MM_PLUGIN_NOKIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_NOKIA, MMPluginNokiaClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginNokia;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginNokiaClass;
+
+GType mm_plugin_nokia_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_NOKIA_H */
diff --git a/plugins/mm-plugin-novatel.c b/plugins/mm-plugin-novatel.c
new file mode 100644
index 0000000..48ff7ec
--- /dev/null
+++ b/plugins/mm-plugin-novatel.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 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <gmodule.h>
+#include "mm-plugin-novatel.h"
+#include "mm-modem-novatel-gsm.h"
+#include "mm-generic-cdma.h"
+
+G_DEFINE_TYPE (MMPluginNovatel, mm_plugin_novatel, 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_NOVATEL,
+ MM_PLUGIN_BASE_NAME, "Novatel",
+ 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;
+ return 0;
+}
+
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
+{
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
+}
+
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
+{
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *subsys, *name, *driver;
+ guint16 vendor = 0;
+
+ /* Can't do anything with non-serial ports */
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ driver = mm_plugin_base_supports_task_get_driver (task);
+ if (!driver || (strcmp (driver, "option1") && strcmp (driver, "option")))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (vendor != 0x1410 && vendor != 0x413c)
+ 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, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
+ guint32 caps;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ devfile = g_udev_device_get_device_file (port);
+ if (!devfile) {
+ g_set_error (error, 0, 0, "Could not get port's sysfs file.");
+ return NULL;
+ }
+
+ 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);
+ 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));
+ }
+
+ if (modem) {
+ if (!mm_modem_grab_port (modem, subsys, name, MM_PORT_TYPE_UNKNOWN, NULL, error)) {
+ g_object_unref (modem);
+ 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;
+ }
+ }
+
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_novatel_init (MMPluginNovatel *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_novatel_class_init (MMPluginNovatelClass *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-novatel.h b/plugins/mm-plugin-novatel.h
new file mode 100644
index 0000000..450bbdd
--- /dev/null
+++ b/plugins/mm-plugin-novatel.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_PLUGIN_NOVATEL_H
+#define MM_PLUGIN_NOVATEL_H
+
+#include "mm-plugin-base.h"
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_PLUGIN_NOVATEL (mm_plugin_novatel_get_type ())
+#define MM_PLUGIN_NOVATEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_NOVATEL, MMPluginNovatel))
+#define MM_PLUGIN_NOVATEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_NOVATEL, MMPluginNovatelClass))
+#define MM_IS_PLUGIN_NOVATEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_NOVATEL))
+#define MM_IS_PLUGIN_NOVATEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_NOVATEL))
+#define MM_PLUGIN_NOVATEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_NOVATEL, MMPluginNovatelClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginNovatel;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginNovatelClass;
+
+GType mm_plugin_novatel_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_NOVATEL_H */
diff --git a/plugins/mm-plugin-option.c b/plugins/mm-plugin-option.c
new file mode 100644
index 0000000..d4c402d
--- /dev/null
+++ b/plugins/mm-plugin-option.c
@@ -0,0 +1,180 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <gmodule.h>
+#include "mm-plugin-option.h"
+#include "mm-modem-option.h"
+
+G_DEFINE_TYPE (MMPluginOption, mm_plugin_option, 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_OPTION,
+ MM_PLUGIN_BASE_NAME, "Option",
+ NULL));
+}
+
+/*****************************************************************************/
+
+static guint32
+get_level_for_capabilities (guint32 capabilities)
+{
+ if (capabilities & MM_PLUGIN_BASE_PORT_CAP_GSM)
+ return 10;
+ return 0;
+}
+
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
+{
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
+}
+
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
+{
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *driver, *subsys, *name;
+ guint16 vendor = 0;
+
+ /* Can't do anything with non-serial ports */
+ port = mm_plugin_base_supports_task_get_port (task);
+ if (strcmp (g_udev_device_get_subsystem (port), "tty"))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ subsys = g_udev_device_get_subsystem (port);
+ name = g_udev_device_get_name (port);
+
+ driver = mm_plugin_base_supports_task_get_driver (task);
+ if (!driver || (strcmp (driver, "option1") && strcmp (driver, "option")))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (!mm_plugin_base_get_device_ids (base, subsys, name, &vendor, NULL))
+ return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED;
+
+ if (vendor != 0x0af0)
+ 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, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
+ guint32 caps;
+ int usbif;
+ MMPortType ptype = MM_PORT_TYPE_SECONDARY;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ devfile = g_udev_device_get_device_file (port);
+ if (!devfile) {
+ g_set_error (error, 0, 0, "Could not get port's sysfs file.");
+ return NULL;
+ }
+
+ 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);
+
+ /* This is the MM equivalent of NM commit 9d7f5b3d084eee2ccfff721c4beca3e3f34bdc50;
+ * Genuine Option NV devices are always supposed to use USB interface 0 as
+ * the modem/data port, per mail with Option engineers. Only this port
+ * will emit responses to dialing commands.
+ */
+ usbif = g_udev_device_get_property_as_int (port, "ID_USB_INTERFACE_NUM");
+ if (usbif == 0)
+ ptype = MM_PORT_TYPE_PRIMARY;
+
+ caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_modem_option_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ }
+
+ if (modem) {
+ if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error)) {
+ g_object_unref (modem);
+ 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;
+ }
+ }
+
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_option_init (MMPluginOption *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_option_class_init (MMPluginOptionClass *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-option.h b/plugins/mm-plugin-option.h
new file mode 100644
index 0000000..dfcff74
--- /dev/null
+++ b/plugins/mm-plugin-option.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_PLUGIN_OPTION_H
+#define MM_PLUGIN_OPTION_H
+
+#include "mm-plugin-base.h"
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_PLUGIN_OPTION (mm_plugin_option_get_type ())
+#define MM_PLUGIN_OPTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_OPTION, MMPluginOption))
+#define MM_PLUGIN_OPTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_OPTION, MMPluginOptionClass))
+#define MM_IS_PLUGIN_OPTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_OPTION))
+#define MM_IS_PLUGIN_OPTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_OPTION))
+#define MM_PLUGIN_OPTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_OPTION, MMPluginOptionClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginOption;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginOptionClass;
+
+GType mm_plugin_option_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_OPTION_H */
diff --git a/plugins/mm-plugin-sierra.c b/plugins/mm-plugin-sierra.c
new file mode 100644
index 0000000..637f46d
--- /dev/null
+++ b/plugins/mm-plugin-sierra.c
@@ -0,0 +1,204 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <gmodule.h>
+#include "mm-plugin-sierra.h"
+#include "mm-modem-sierra-gsm.h"
+#include "mm-modem-sierra-cdma.h"
+
+G_DEFINE_TYPE (MMPluginSierra, mm_plugin_sierra, 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_SIERRA,
+ MM_PLUGIN_BASE_NAME, "Sierra",
+ NULL));
+}
+
+/*****************************************************************************/
+
+#define TAG_SIERRA_SECONDARY_PORT "sierra-secondary-port"
+
+#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;
+ return 0;
+}
+
+static void
+handle_probe_response (MMPluginBase *self,
+ MMPluginBaseSupportsTask *task,
+ const char *cmd,
+ const char *response,
+ const GError *error)
+{
+ if (error || !response || strcmp (cmd, "I")) {
+ MM_PLUGIN_BASE_CLASS (mm_plugin_sierra_parent_class)->handle_probe_response (self, task, cmd, response, error);
+ return;
+ }
+
+ if (strstr (response, "APP1") || strstr (response, "APP2") || strstr (response, "APP3")) {
+ g_object_set_data (G_OBJECT (task), TAG_SIERRA_SECONDARY_PORT, GUINT_TO_POINTER (TRUE));
+ mm_plugin_base_supports_task_complete (task, 10);
+ return;
+ }
+
+ /* Not an app port, let the superclass handle the response */
+ MM_PLUGIN_BASE_CLASS (mm_plugin_sierra_parent_class)->handle_probe_response (self, task, cmd, response, error);
+}
+
+static void
+probe_result (MMPluginBase *base,
+ MMPluginBaseSupportsTask *task,
+ guint32 capabilities,
+ gpointer user_data)
+{
+ mm_plugin_base_supports_task_complete (task, get_level_for_capabilities (capabilities));
+}
+
+static MMPluginSupportsResult
+supports_port (MMPluginBase *base,
+ MMModem *existing,
+ MMPluginBaseSupportsTask *task)
+{
+ GUdevDevice *port;
+ guint32 cached = 0, level;
+ const char *driver;
+
+ /* 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;
+
+ driver = mm_plugin_base_supports_task_get_driver (task);
+ if (!driver || strcmp (driver, "sierra"))
+ 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, *physdev = NULL;
+ MMModem *modem = NULL;
+ const char *name, *subsys, *devfile, *sysfs_path;
+ guint32 caps;
+ MMPortType ptype = MM_PORT_TYPE_UNKNOWN;
+
+ port = mm_plugin_base_supports_task_get_port (task);
+ g_assert (port);
+
+ devfile = g_udev_device_get_device_file (port);
+ if (!devfile) {
+ g_set_error (error, 0, 0, "Could not get port's sysfs file.");
+ return NULL;
+ }
+
+ 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);
+
+ /* Is it a GSM secondary port? */
+ if (g_object_get_data (G_OBJECT (task), TAG_SIERRA_SECONDARY_PORT))
+ ptype = MM_PORT_TYPE_SECONDARY;
+
+ caps = mm_plugin_base_supports_task_get_probed_capabilities (task);
+ if (!existing) {
+ if ((caps & MM_PLUGIN_BASE_PORT_CAP_GSM) || (ptype != MM_PORT_TYPE_UNKNOWN)) {
+ modem = mm_modem_sierra_gsm_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ } else if (caps & CAP_CDMA) {
+ modem = mm_modem_sierra_cdma_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856),
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A));
+ }
+
+ if (modem) {
+ if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error)) {
+ g_object_unref (modem);
+ 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;
+ }
+ }
+
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_sierra_init (MMPluginSierra *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_sierra_class_init (MMPluginSierraClass *klass)
+{
+ MMPluginBaseClass *pb_class = MM_PLUGIN_BASE_CLASS (klass);
+
+ pb_class->supports_port = supports_port;
+ pb_class->grab_port = grab_port;
+ pb_class->handle_probe_response = handle_probe_response;
+}
diff --git a/plugins/mm-plugin-sierra.h b/plugins/mm-plugin-sierra.h
new file mode 100644
index 0000000..01fffc4
--- /dev/null
+++ b/plugins/mm-plugin-sierra.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_PLUGIN_SIERRA_H
+#define MM_PLUGIN_SIERRA_H
+
+#include "mm-plugin-base.h"
+#include "mm-generic-gsm.h"
+
+#define MM_TYPE_PLUGIN_SIERRA (mm_plugin_sierra_get_type ())
+#define MM_PLUGIN_SIERRA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_SIERRA, MMPluginSierra))
+#define MM_PLUGIN_SIERRA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_SIERRA, MMPluginSierraClass))
+#define MM_IS_PLUGIN_SIERRA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_SIERRA))
+#define MM_IS_PLUGIN_SIERRA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_SIERRA))
+#define MM_PLUGIN_SIERRA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_SIERRA, MMPluginSierraClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginSierra;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginSierraClass;
+
+GType mm_plugin_sierra_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_SIERRA_H */
diff --git a/plugins/mm-plugin-zte.c b/plugins/mm-plugin-zte.c
new file mode 100644
index 0000000..101fb46
--- /dev/null
+++ b/plugins/mm-plugin-zte.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 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <gmodule.h>
+#include "mm-plugin-zte.h"
+#include "mm-modem-zte.h"
+#include "mm-generic-cdma.h"
+
+G_DEFINE_TYPE (MMPluginZte, mm_plugin_zte, 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_ZTE,
+ MM_PLUGIN_BASE_NAME, "ZTE",
+ 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;
+ 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;
+
+ if (vendor != 0x19d2)
+ 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 */
+
+ /* Many ZTE devices will flood the port with "Message waiting" indications
+ * and eventually fill up the serial buffer and crash. We need to turn off
+ * that indicator. See NetworkManager commits
+ * 1235f71b20c92cded4abd976ccc5010649aae1a0 and
+ * f38ad328acfdc6ce29dd1380602c546b064161ae for more details.
+ */
+ mm_plugin_base_supports_task_set_custom_init_command (task, "ATE0+CPMS?", 3, 4, TRUE);
+
+ 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, *physdev = 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 */
+ if (g_udev_device_get_property_as_boolean (port, "ID_MM_ZTE_PORT_TYPE_MODEM"))
+ ptype = MM_PORT_TYPE_PRIMARY;
+ 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);
+ if (!existing) {
+ if (caps & MM_PLUGIN_BASE_PORT_CAP_GSM) {
+ modem = mm_modem_zte_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)));
+ } 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 (caps & (MM_PLUGIN_BASE_PORT_CAP_GSM | CAP_CDMA)) {
+ modem = existing;
+ if (!mm_modem_grab_port (modem, subsys, name, ptype, NULL, error))
+ return NULL;
+ }
+ }
+
+ return modem;
+}
+
+/*****************************************************************************/
+
+static void
+mm_plugin_zte_init (MMPluginZte *self)
+{
+ g_signal_connect (self, "probe-result", G_CALLBACK (probe_result), NULL);
+}
+
+static void
+mm_plugin_zte_class_init (MMPluginZteClass *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-zte.h b/plugins/mm-plugin-zte.h
new file mode 100644
index 0000000..7a4d4c9
--- /dev/null
+++ b/plugins/mm-plugin-zte.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_PLUGIN_ZTE_H
+#define MM_PLUGIN_ZTE_H
+
+#include "mm-plugin-base.h"
+
+#define MM_TYPE_PLUGIN_ZTE (mm_plugin_zte_get_type ())
+#define MM_PLUGIN_ZTE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_ZTE, MMPluginZte))
+#define MM_PLUGIN_ZTE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_ZTE, MMPluginZteClass))
+#define MM_IS_PLUGIN_ZTE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_ZTE))
+#define MM_IS_PLUGIN_ZTE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_ZTE))
+#define MM_PLUGIN_ZTE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_ZTE, MMPluginZteClass))
+
+typedef struct {
+ MMPluginBase parent;
+} MMPluginZte;
+
+typedef struct {
+ MMPluginBaseClass parent;
+} MMPluginZteClass;
+
+GType mm_plugin_zte_get_type (void);
+
+G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
+
+#endif /* MM_PLUGIN_ZTE_H */