diff options
57 files changed, 2432 insertions, 529 deletions
diff --git a/Makefile.am b/Makefile.am index 1c65967e..4132bc92 100644 --- a/Makefile.am +++ b/Makefile.am @@ -80,6 +80,7 @@ DISTCLEANFILES = \ EXTRA_DIST = \ doc-generator.xsl \ + header-generator.xsl \ $(dbusactivation_in_files) \ $(INTLTOOL_FILES) \ $(dbusservice_file_polkit) \ diff --git a/introspection/Makefile.am b/introspection/Makefile.am index 5c2a5ebb..3c7a380e 100644 --- a/introspection/Makefile.am +++ b/introspection/Makefile.am @@ -1,19 +1,19 @@ EXTRA_DIST = \ all.xml \ - mm-manager.xml \ + org.freedesktop.ModemManager.xml \ mm-mobile-error.xml \ - mm-modem.xml \ - mm-modem-cdma.xml \ + org.freedesktop.ModemManager.Modem.xml \ + org.freedesktop.ModemManager.Modem.Cdma.xml \ mm-modem-connect-error.xml \ mm-modem-error.xml \ - mm-modem-gsm.xml \ - mm-modem-gsm-card.xml \ - mm-modem-gsm-contacts.xml \ - mm-modem-gsm-hso.xml \ - mm-modem-gsm-network.xml \ - mm-modem-gsm-sms.xml \ - mm-modem-simple.xml \ + org.freedesktop.ModemManager.Modem.Gsm.xml \ + org.freedesktop.ModemManager.Modem.Gsm.Card.xml \ + org.freedesktop.ModemManager.Modem.Gsm.Contacts.xml \ + org.freedesktop.ModemManager.Modem.Gsm.Hso.xml \ + org.freedesktop.ModemManager.Modem.Gsm.Network.xml \ + org.freedesktop.ModemManager.Modem.Gsm.SMS.xml \ + org.freedesktop.ModemManager.Modem.Simple.xml \ mm-serial-error.xml \ - mm-modem-location.xml \ - mm-modem-gsm-ussd.xml \ - mm-properties-changed.xml + org.freedesktop.ModemManager.Modem.Location.xml \ + org.freedesktop.ModemManager.Modem.Gsm.Ussd.xml \ + org.freedesktop.DBus.Properties.xml diff --git a/introspection/org.freedesktop.ModemManager.Modem.Cdma.xml b/introspection/org.freedesktop.ModemManager.Modem.Cdma.xml index 3e4c98b7..d80d9b9b 100644 --- a/introspection/org.freedesktop.ModemManager.Modem.Cdma.xml +++ b/introspection/org.freedesktop.ModemManager.Modem.Cdma.xml @@ -120,7 +120,7 @@ </arg> </method> - <property name="MEID" type="s" access="read"> + <property name="Meid" type="s" access="read"> <tp:docstring> The modem's Mobile Equipment Identifier. </tp:docstring> diff --git a/introspection/org.freedesktop.ModemManager.Modem.Gsm.Ussd.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Ussd.xml index ae6884f0..8eef91d2 100644 --- a/introspection/org.freedesktop.ModemManager.Modem.Gsm.Ussd.xml +++ b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Ussd.xml @@ -38,6 +38,12 @@ request for further input. </tp:docstring> </arg> + <arg name="reply" type="s" direction="out"> + <tp:docstring> + The network reply to this response to the network-initiated USSD + command. The reply may require further responses. + </tp:docstring> + </arg> </method> <method name="Cancel"> diff --git a/introspection/org.freedesktop.ModemManager.Modem.Gsm.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.xml index ea23adcf..78da9a44 100644 --- a/introspection/org.freedesktop.ModemManager.Modem.Gsm.xml +++ b/introspection/org.freedesktop.ModemManager.Modem.Gsm.xml @@ -157,6 +157,9 @@ <tp:enumvalue suffix="HSPA" value="8"> <tp:docstring>HSPA (ETSI 27.007: "UTRAN w/HSDPA and HSUPA")</tp:docstring> </tp:enumvalue> + <tp:enumvalue suffix="HSPA_PLUS" value="9"> + <tp:docstring>HSPA+ (ETSI 27.007: "UTRAN w/HSPA+")</tp:docstring> + </tp:enumvalue> </tp:enum> </interface> diff --git a/introspection/org.freedesktop.ModemManager.Modem.xml b/introspection/org.freedesktop.ModemManager.Modem.xml index e1a07293..d5da9525 100644 --- a/introspection/org.freedesktop.ModemManager.Modem.xml +++ b/introspection/org.freedesktop.ModemManager.Modem.xml @@ -63,9 +63,20 @@ </arg> </method> + <method name="Reset"> + <tp:docstring> + Clear non-persistent configuration and state, and return the device to + a newly-powered-on state. This command may power-cycle the device. + </tp:docstring> + <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_reset"/> + </method> + <method name="FactoryReset"> <tp:docstring> - Reset the modem to as close to factory state as possible. + Clear the modem's configuration (including persistent configuration and + state), and return the device to a factory-default state. This command + may or may not power-cycle the device. </tp:docstring> <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_factory_reset"/> diff --git a/libqcdm/src/commands.c b/libqcdm/src/commands.c index 47b517de..ab61ee51 100644 --- a/libqcdm/src/commands.c +++ b/libqcdm/src/commands.c @@ -873,6 +873,107 @@ qcdm_cmd_nv_set_mode_pref_result (const char *buf, gsize len, GError **error) /**********************************************************************/ +static gboolean +hdr_rev_pref_validate (guint8 dm) +{ + if ( dm == DIAG_NV_HDR_REV_PREF_0 + || dm == DIAG_NV_HDR_REV_PREF_A + || dm == DIAG_NV_HDR_REV_PREF_EHRPD) + return TRUE; + return FALSE; +} + +gsize +qcdm_cmd_nv_get_hdr_rev_pref_new (char *buf, gsize len, GError **error) +{ + char cmdbuf[sizeof (DMCmdNVReadWrite) + 2]; + DMCmdNVReadWrite *cmd = (DMCmdNVReadWrite *) &cmdbuf[0]; + + g_return_val_if_fail (buf != NULL, 0); + g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + + memset (cmd, 0, sizeof (*cmd)); + cmd->code = DIAG_CMD_NV_READ; + cmd->nv_item = GUINT16_TO_LE (DIAG_NV_HDR_REV_PREF); + + return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); +} + +QCDMResult * +qcdm_cmd_nv_get_hdr_rev_pref_result (const char *buf, gsize len, GError **error) +{ + QCDMResult *result = NULL; + DMCmdNVReadWrite *rsp = (DMCmdNVReadWrite *) buf; + DMNVItemHdrRevPref *rev; + + g_return_val_if_fail (buf != NULL, NULL); + + if (!check_command (buf, len, DIAG_CMD_NV_READ, sizeof (DMCmdNVReadWrite), error)) + return NULL; + + if (!check_nv_cmd (rsp, DIAG_NV_HDR_REV_PREF, error)) + return NULL; + + rev = (DMNVItemHdrRevPref *) &rsp->data[0]; + + if (!hdr_rev_pref_validate (rev->rev_pref)) { + g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_PARAMETER, + "Unknown HDR revision preference 0x%X", + rev->rev_pref); + return NULL; + } + + result = qcdm_result_new (); + qcdm_result_add_uint8 (result, QCDM_CMD_NV_GET_HDR_REV_PREF_ITEM_REV_PREF, rev->rev_pref); + + return result; +} + +gsize +qcdm_cmd_nv_set_hdr_rev_pref_new (char *buf, + gsize len, + guint8 rev_pref, + GError **error) +{ + char cmdbuf[sizeof (DMCmdNVReadWrite) + 2]; + DMCmdNVReadWrite *cmd = (DMCmdNVReadWrite *) &cmdbuf[0]; + DMNVItemHdrRevPref *req; + + g_return_val_if_fail (buf != NULL, 0); + g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0); + + if (!hdr_rev_pref_validate (rev_pref)) { + g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_PARAMETER, + "Invalid HDR revision preference %d", rev_pref); + return 0; + } + + memset (cmd, 0, sizeof (*cmd)); + cmd->code = DIAG_CMD_NV_WRITE; + cmd->nv_item = GUINT16_TO_LE (DIAG_NV_HDR_REV_PREF); + + req = (DMNVItemHdrRevPref *) &cmd->data[0]; + req->rev_pref = rev_pref; + + return dm_encapsulate_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len); +} + +QCDMResult * +qcdm_cmd_nv_set_hdr_rev_pref_result (const char *buf, gsize len, GError **error) +{ + g_return_val_if_fail (buf != NULL, NULL); + + if (!check_command (buf, len, DIAG_CMD_NV_WRITE, sizeof (DMCmdNVReadWrite), error)) + return NULL; + + if (!check_nv_cmd ((DMCmdNVReadWrite *) buf, DIAG_NV_HDR_REV_PREF, error)) + return NULL; + + return qcdm_result_new (); +} + +/**********************************************************************/ + gsize qcdm_cmd_cm_subsys_state_info_new (char *buf, gsize len, GError **error) { diff --git a/libqcdm/src/commands.h b/libqcdm/src/commands.h index 50a6f49a..fe582a68 100644 --- a/libqcdm/src/commands.h +++ b/libqcdm/src/commands.h @@ -300,6 +300,34 @@ QCDMResult *qcdm_cmd_nv_set_mode_pref_result (const char *buf, /**********************************************************************/ +/* Values for QCDM_CMD_NV_GET_HDR_REV_PREF_ITEM_REV_PREF */ +enum { + QCDM_CMD_NV_HDR_REV_PREF_ITEM_REV_PREF_0 = 0x00, + QCDM_CMD_NV_HDR_REV_PREF_ITEM_REV_PREF_A = 0x01, + QCDM_CMD_NV_HDR_REV_PREF_ITEM_REV_PREF_EHRPD = 0x04, +}; + +#define QCDM_CMD_NV_GET_HDR_REV_PREF_ITEM_REV_PREF "rev-pref" + +gsize qcdm_cmd_nv_get_hdr_rev_pref_new (char *buf, + gsize len, + GError **error); + +QCDMResult *qcdm_cmd_nv_get_hdr_rev_pref_result (const char *buf, + gsize len, + GError **error); + +gsize qcdm_cmd_nv_set_hdr_rev_pref_new (char *buf, + gsize len, + guint8 rev_pref, + GError **error); + +QCDMResult *qcdm_cmd_nv_set_hdr_rev_pref_result (const char *buf, + gsize len, + GError **error); + +/**********************************************************************/ + /* Values for QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_OPERATING_MODE */ enum { QCDM_CMD_CM_SUBSYS_STATE_INFO_OPERATING_MODE_ONLINE = 5 @@ -313,7 +341,10 @@ enum { QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_GSM = 3, QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_HDR = 4, QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_WCDMA = 5, - QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_GPS = 6 + QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_GPS = 6, + QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_GW = 7, /* GSM & WCDMA */ + QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_WLAN = 8, + QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_LTE = 9, }; /* Values for QCDM_CMD_CM_SUBSYS_STATE_INFO_ITEM_ROAM_PREF */ diff --git a/libqcdm/src/nv-items.h b/libqcdm/src/nv-items.h index a0ca10a6..8240866a 100644 --- a/libqcdm/src/nv-items.h +++ b/libqcdm/src/nv-items.h @@ -19,17 +19,21 @@ #define LIBQCDM_NV_ITEMS_H enum { - DIAG_NV_MODE_PREF = 10, /* Mode preference: 1x, HDR, auto */ - DIAG_NV_DIR_NUMBER = 178, /* Mobile Directory Number (MDN) */ - DIAG_NV_ROAM_PREF = 442, /* Roaming preference */ + DIAG_NV_MODE_PREF = 10, /* Mode preference: 1x, HDR, auto */ + DIAG_NV_DIR_NUMBER = 178, /* Mobile Directory Number (MDN) */ + DIAG_NV_ROAM_PREF = 442, /* Roaming preference */ + DIAG_NV_HDR_REV_PREF = 4964, /* HDR mode preference(?): rev0, revA, eHRPD */ }; /* Mode preference values */ enum { - DIAG_NV_MODE_PREF_AUTO = 0x04, - DIAG_NV_MODE_PREF_1X_ONLY = 0x09, - DIAG_NV_MODE_PREF_HDR_ONLY = 0x0A, + DIAG_NV_MODE_PREF_AUTO = 0x04, + DIAG_NV_MODE_PREF_1X_ONLY = 0x09, + DIAG_NV_MODE_PREF_HDR_ONLY = 0x0A, + DIAG_NV_MODE_PREF_1X_HDR_ONLY = 0x0D, + DIAG_NV_MODE_PREF_LTE_ONLY = 0x1E, + DIAG_NV_MODE_PREF_1X_HDR_LTE_ONLY = 0x24, }; /* DIAG_NV_MODE_PREF */ @@ -60,5 +64,18 @@ struct DMNVItemRoamPref { } __attribute__ ((packed)); typedef struct DMNVItemRoamPref DMNVItemRoamPref; +/* HDR Revision preference values (?) */ +enum { + DIAG_NV_HDR_REV_PREF_0 = 0x00, + DIAG_NV_HDR_REV_PREF_A = 0x01, + DIAG_NV_HDR_REV_PREF_EHRPD = 0x04, +}; + +/* DIAG_NV_HDR_REV_PREF */ +struct DMNVItemHdrRevPref { + guint8 rev_pref; +} __attribute__ ((packed)); +typedef struct DMNVItemHdrRevPref DMNVItemHdrRevPref; + #endif /* LIBQCDM_NV_ITEMS_H */ diff --git a/libqcdm/tests/test-qcdm-com.c b/libqcdm/tests/test-qcdm-com.c index 8e6113bd..b95c7d9b 100644 --- a/libqcdm/tests/test-qcdm-com.c +++ b/libqcdm/tests/test-qcdm-com.c @@ -575,6 +575,62 @@ test_com_read_mode_pref (void *f, void *data) } void +test_com_read_hdr_rev_pref (void *f, void *data) +{ + TestComData *d = data; + gboolean success; + GError *error = NULL; + char buf[512]; + guint8 pref; + const char *msg; + gint len; + QCDMResult *result; + gsize reply_len; + + len = qcdm_cmd_nv_get_hdr_rev_pref_new (buf, sizeof (buf), NULL); + g_assert (len > 0); + + /* Send the command */ + success = send_command (d, buf, len); + g_assert (success); + + /* Get a response */ + reply_len = wait_reply (d, buf, sizeof (buf)); + + /* Parse the response into a result structure */ + result = qcdm_cmd_nv_get_hdr_rev_pref_result (buf, reply_len, &error); + if (!result) { + g_assert (error); + g_assert (error->domain == QCDM_COMMAND_ERROR); + g_assert (error->code == QCDM_COMMAND_NVCMD_FAILED || error->code == QCDM_COMMAND_BAD_PARAMETER); + return; + } + + g_print ("\n"); + + success = qcdm_result_get_uint8 (result, QCDM_CMD_NV_GET_HDR_REV_PREF_ITEM_REV_PREF, &pref); + g_assert (success); + + switch (pref) { + case QCDM_CMD_NV_HDR_REV_PREF_ITEM_REV_PREF_0: + msg = "rev0"; + break; + case QCDM_CMD_NV_HDR_REV_PREF_ITEM_REV_PREF_A: + msg = "revA"; + break; + case QCDM_CMD_NV_HDR_REV_PREF_ITEM_REV_PREF_EHRPD: + msg = "eHRPD"; + break; + default: + msg = "unknown"; + break; + } + g_message ("%s: HDR rev preference: 0x%02X (%s)", __func__, pref, msg); + + qcdm_result_unref (result); +} + +void test_com_status (void *f, void *data) { TestComData *d = data; @@ -906,6 +962,9 @@ test_com_cm_subsys_state_info (void *f, void *data) case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_WCDMA: detail = "WCDMA"; break; + case QCDM_CMD_CM_SUBSYS_STATE_INFO_SYSTEM_MODE_LTE: + detail = "LTE"; + break; default: detail = "unknown"; break; diff --git a/libqcdm/tests/test-qcdm-com.h b/libqcdm/tests/test-qcdm-com.h index 6b1f4ba7..76075e54 100644 --- a/libqcdm/tests/test-qcdm-com.h +++ b/libqcdm/tests/test-qcdm-com.h @@ -33,6 +33,8 @@ void test_com_read_roam_pref (void *f, void *data); void test_com_read_mode_pref (void *f, void *data); +void test_com_read_hdr_rev_pref (void *f, void *data); + void test_com_status (void *f, void *data); void test_com_sw_version (void *f, void *data); diff --git a/libqcdm/tests/test-qcdm.c b/libqcdm/tests/test-qcdm.c index 5867bcb9..946fb673 100644 --- a/libqcdm/tests/test-qcdm.c +++ b/libqcdm/tests/test-qcdm.c @@ -102,6 +102,7 @@ int main (int argc, char **argv) g_test_suite_add (suite, TESTCASE (test_com_mdn, data->com_data)); g_test_suite_add (suite, TESTCASE (test_com_read_roam_pref, data->com_data)); g_test_suite_add (suite, TESTCASE (test_com_read_mode_pref, data->com_data)); + g_test_suite_add (suite, TESTCASE (test_com_read_hdr_rev_pref, data->com_data)); g_test_suite_add (suite, TESTCASE (test_com_status, data->com_data)); g_test_suite_add (suite, TESTCASE (test_com_sw_version, data->com_data)); g_test_suite_add (suite, TESTCASE (test_com_status_snapshot, data->com_data)); diff --git a/plugins/77-mm-zte-port-types.rules b/plugins/77-mm-zte-port-types.rules index bc6f05a9..072154ce 100644 --- a/plugins/77-mm-zte-port-types.rules +++ b/plugins/77-mm-zte-port-types.rules @@ -78,6 +78,9 @@ ATTRS{idProduct}=="0033", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}= ATTRS{idProduct}=="0037", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0037", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" +ATTRS{idProduct}=="0039", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" +ATTRS{idProduct}=="0039", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" + ATTRS{idProduct}=="0042", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0042", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" @@ -93,9 +96,15 @@ ATTRS{idProduct}=="0049", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_AUX}= ATTRS{idProduct}=="0052", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0052", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" +ATTRS{idProduct}=="0054", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" +ATTRS{idProduct}=="0054", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" + ATTRS{idProduct}=="0055", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0055", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" +ATTRS{idProduct}=="0057", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" +ATTRS{idProduct}=="0057", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" + ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" @@ -108,9 +117,15 @@ ATTRS{idProduct}=="0064", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_ZTE_PORT_TYPE_AUX}= ATTRS{idProduct}=="0066", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0066", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" +ATTRS{idProduct}=="0082", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" +ATTRS{idProduct}=="0082", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" + ATTRS{idProduct}=="0104", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0104", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" +ATTRS{idProduct}=="0108", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" +ATTRS{idProduct}=="0108", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" + ATTRS{idProduct}=="0113", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_ZTE_PORT_TYPE_MODEM}="1" ATTRS{idProduct}=="0113", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_ZTE_PORT_TYPE_AUX}="1" diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 9f85d54f..dd58b943 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -1,3 +1,24 @@ + +########################## +# Icera-specific support # +########################## + +noinst_LTLIBRARIES = libicera-utils.la + +libicera_utils_la_SOURCES = \ + mm-modem-icera.c \ + mm-modem-icera.h + +libicera_utils_la_CPPFLAGS = \ + $(MM_CFLAGS) \ + $(GUDEV_CFLAGS) \ + -I$(top_srcdir)/src + +libicera_utils_la_LIBADD = \ + $(GUDEV_LDFLAGS) + +######################################## + pkglib_LTLIBRARIES = \ libmm-plugin-generic.la \ libmm-plugin-moto-c.la \ @@ -220,6 +241,7 @@ libmm_plugin_zte_la_CPPFLAGS = \ libmm_plugin_zte_la_LDFLAGS = \ $(GUDEV_LDFLAGS) \ + $(builddir)/libicera-utils.la \ -module \ -avoid-version diff --git a/plugins/mm-modem-anydata-cdma.c b/plugins/mm-modem-anydata-cdma.c index 3bf15ed8..0e7e65c5 100644 --- a/plugins/mm-modem-anydata-cdma.c +++ b/plugins/mm-modem-anydata-cdma.c @@ -28,6 +28,7 @@ #include "mm-callback-info.h" #include "mm-serial-port.h" #include "mm-serial-parsers.h" +#include "mm-log.h" static void modem_init (MMModem *modem_class); @@ -140,7 +141,7 @@ evdo_state_done (MMAtSerialPort *port, G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); if (!r) { /* Parse error; warn about it and assume EVDO is not available */ - g_warning ("AnyDATA(%s): *HSTATE parse regex creation failed.", __func__); + mm_warn ("ANYDATA: *HSTATE parse regex creation failed."); goto done; } @@ -167,7 +168,7 @@ evdo_state_done (MMAtSerialPort *port, reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; break; default: - g_message ("ANYDATA: unknown *STATE (%d); assuming no service.", val); + mm_warn ("ANYDATA: unknown *STATE (%d); assuming no service.", val); /* fall through */ case 0: /* NO SERVICE */ case 1: /* ACQUISITION */ @@ -206,7 +207,7 @@ state_done (MMAtSerialPort *port, r = g_regex_new ("\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*([^,\\)]*)\\s*,.*", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); if (!r) { - g_warning ("AnyDATA(%s): *STATE parse regex creation failed.", __func__); + mm_warn ("ANYDATA: *STATE parse regex creation failed."); mm_callback_info_schedule (info); return; } @@ -235,7 +236,7 @@ state_done (MMAtSerialPort *port, reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; break; default: - g_warning ("ANYDATA: unknown *STATE (%d); assuming no service.", val); + mm_warn ("ANYDATA: unknown *STATE (%d); assuming no service.", val); /* fall through */ case 0: /* NO SERVICE */ break; @@ -272,6 +273,24 @@ query_registration_state (MMGenericCdma *cdma, /*****************************************************************************/ +static void +reset (MMModem *modem, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + MMAtSerialPort *port; + + info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); + + /* Ensure we have a usable port to use for the command */ + port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (modem), &info->error); + if (port) + mm_at_serial_port_queue_command (port, "*RESET", 3, NULL, NULL); + + mm_callback_info_schedule (info); +} + static gboolean grab_port (MMModem *modem, const char *subsys, @@ -333,6 +352,7 @@ static void modem_init (MMModem *modem_class) { modem_class->grab_port = grab_port; + modem_class->reset = reset; } static void diff --git a/plugins/mm-modem-huawei-cdma.c b/plugins/mm-modem-huawei-cdma.c index 7faa9f08..3aec470b 100644 --- a/plugins/mm-modem-huawei-cdma.c +++ b/plugins/mm-modem-huawei-cdma.c @@ -27,6 +27,7 @@ #include "mm-callback-info.h" #include "mm-serial-port.h" #include "mm-serial-parsers.h" +#include "mm-log.h" static void modem_init (MMModem *modem_class); @@ -79,7 +80,7 @@ parse_quality (const char *str, const char *detail) quality = strtol (str, NULL, 10); if (errno == 0) { quality = CLAMP (quality, 0, 100); - g_debug ("%s: %ld", detail, quality); + mm_dbg ("%s: %ld", detail, quality); return (gint) quality; } return -1; @@ -177,7 +178,7 @@ sysinfo_done (MMAtSerialPort *port, r = g_regex_new ("\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); if (!r) { - g_warning ("Huawei(%s): ^SYSINFO parse regex creation failed.", __func__); + mm_warn ("Huawei: ^SYSINFO parse regex creation failed."); goto done; } @@ -218,7 +219,7 @@ sysinfo_done (MMAtSerialPort *port, mm_generic_cdma_query_reg_state_set_callback_1x_state (info, reg_state); } } else - g_warning ("Huawei(%s): failed to parse ^SYSINFO response.", __func__); + mm_warn ("Huawei: failed to parse ^SYSINFO response."); g_match_info_free (match_info); g_regex_unref (r); diff --git a/plugins/mm-modem-huawei-gsm.c b/plugins/mm-modem-huawei-gsm.c index cde4b4a2..3fc9ae26 100644 --- a/plugins/mm-modem-huawei-gsm.c +++ b/plugins/mm-modem-huawei-gsm.c @@ -29,7 +29,7 @@ #include "mm-callback-info.h" #include "mm-at-serial-port.h" #include "mm-serial-parsers.h" -#include "mm-options.h" +#include "mm-log.h" static void modem_init (MMModem *modem_class); static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class); @@ -367,6 +367,35 @@ get_band (MMModemGsmNetwork *modem, mm_at_serial_port_queue_command (port, "AT^SYSCFG?", 3, get_band_done, info); } +static MMModemGsmAccessTech +huawei_sysinfo_to_act (int huawei) +{ + switch (huawei) { + case 1: + return MM_MODEM_GSM_ACCESS_TECH_GSM; + case 2: + return MM_MODEM_GSM_ACCESS_TECH_GPRS; + case 3: + return MM_MODEM_GSM_ACCESS_TECH_EDGE; + case 4: + return MM_MODEM_GSM_ACCESS_TECH_UMTS; + case 5: + return MM_MODEM_GSM_ACCESS_TECH_HSDPA; + case 6: + return MM_MODEM_GSM_ACCESS_TECH_HSUPA; + case 7: + return MM_MODEM_GSM_ACCESS_TECH_HSPA; + case 9: + return MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS; + case 8: + /* TD-SCDMA */ + default: + break; + } + + return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; +} + static void get_act_request_done (MMAtSerialPort *port, GString *response, @@ -409,22 +438,8 @@ get_act_request_done (MMAtSerialPort *port, if (srv_stat != 0) { /* Valid service */ str = g_match_info_fetch (match_info, 7); - if (str && strlen (str)) { - if (str[0] == '1') - act = MM_MODEM_GSM_ACCESS_TECH_GSM; - else if (str[0] == '2') - act = MM_MODEM_GSM_ACCESS_TECH_GPRS; - else if (str[0] == '3') - act = MM_MODEM_GSM_ACCESS_TECH_EDGE; - else if (str[0] == '4') - act = MM_MODEM_GSM_ACCESS_TECH_UMTS; - else if (str[0] == '5') - act = MM_MODEM_GSM_ACCESS_TECH_HSDPA; - else if (str[0] == '6') - act = MM_MODEM_GSM_ACCESS_TECH_HSUPA; - else if (str[0] == '7') - act = MM_MODEM_GSM_ACCESS_TECH_HSPA; - } + if (str && strlen (str)) + act = huawei_sysinfo_to_act (atoi (str)); g_free (str); } @@ -519,7 +534,7 @@ send_huawei_cpin_done (MMAtSerialPort *port, else if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PIN2)) num = 5; else { - g_debug ("%s: unhandled pin type '%s'", __func__, pin_type); + mm_dbg ("unhandled pin type '%s'", pin_type); info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Unhandled PIN type"); } @@ -561,7 +576,7 @@ get_unlock_retries (MMModemGsmCard *modem, char *command; MMCallbackInfo *info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); - g_debug ("%s: pin type '%s'", __func__, pin_type); + mm_dbg ("pin type '%s'", pin_type); /* Ensure we have a usable port to use for the command */ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error); @@ -627,40 +642,30 @@ handle_mode_change (MMAtSerialPort *port, MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; char *str; int a; - int b; str = g_match_info_fetch (match_info, 1); a = atoi (str); g_free (str); str = g_match_info_fetch (match_info, 2); - b = atoi (str); + act = huawei_sysinfo_to_act (atoi (str)); g_free (str); if (a == 3) { /* GSM/GPRS mode */ - if (b == 1) - act = MM_MODEM_GSM_ACCESS_TECH_GSM; - else if (b == 2) - act = MM_MODEM_GSM_ACCESS_TECH_GPRS; - else if (b == 3) - act = MM_MODEM_GSM_ACCESS_TECH_EDGE; + if (act > MM_MODEM_GSM_ACCESS_TECH_EDGE) + act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; } else if (a == 5) { /* WCDMA mode */ - if (b == 4) - act = MM_MODEM_GSM_ACCESS_TECH_UMTS; - else if (b == 5) - act = MM_MODEM_GSM_ACCESS_TECH_HSDPA; - else if (b == 6) - act = MM_MODEM_GSM_ACCESS_TECH_HSUPA; - else if (b == 7) - act = MM_MODEM_GSM_ACCESS_TECH_HSPA; + if (act < MM_MODEM_GSM_ACCESS_TECH_UMTS) + act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; } else if (a == 0) act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; else { - g_warning ("Couldn't parse mode change value: '%s'", str); + mm_warn ("Couldn't parse mode change value: '%s'", str); return; } - g_debug ("Access Technology: %d", act); + mm_dbg ("Access Technology: %d", act); + mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (self), act); } @@ -674,10 +679,8 @@ handle_status_change (MMAtSerialPort *port, str = g_match_info_fetch (match_info, 1); if (sscanf (str, "%x,%x,%x,%x,%x,%x,%x", &n1, &n2, &n3, &n4, &n5, &n6, &n7)) { - if (mm_options_debug ()) { - g_debug ("Duration: %d Up: %d Kbps Down: %d Kbps Total: %d Total: %d\n", - n1, n2 * 8 / 1000, n3 * 8 / 1000, n4 / 1024, n5 / 1024); - } + mm_dbg ("Duration: %d Up: %d Kbps Down: %d Kbps Total: %d Total: %d\n", + n1, n2 * 8 / 1000, n3 * 8 / 1000, n4 / 1024, n5 / 1024); } g_free (str); } diff --git a/plugins/mm-modem-icera.c b/plugins/mm-modem-icera.c new file mode 100644 index 00000000..3f71c5b6 --- /dev/null +++ b/plugins/mm-modem-icera.c @@ -0,0 +1,794 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details: + * + * Copyright (C) 2010 Red Hat, Inc. + */ + +/****************************************** + * Generic utilities for Icera-based modems + ******************************************/ + +#include <config.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <arpa/inet.h> + +#include "mm-modem-icera.h" + +#include "mm-modem.h" +#include "mm-errors.h" +#include "mm-callback-info.h" +#include "mm-at-serial-port.h" +#include "mm-generic-gsm.h" +#include "mm-modem-helpers.h" +#include "mm-log.h" + +struct _MMModemIceraPrivate { + /* Pending connection attempt */ + MMCallbackInfo *connect_pending_data; + guint connect_pending_id; + + char *username; + char *password; + + MMModemGsmAccessTech last_act; +}; + +#define MM_MODEM_ICERA_GET_PRIVATE(m) (MM_MODEM_ICERA_GET_INTERFACE(m)->priv) + +static void +get_allowed_mode_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + gboolean parsed = FALSE; + + if (error) + info->error = g_error_copy (error); + else if (!g_str_has_prefix (response->str, "%IPSYS: ")) { + int a, b; + + if (sscanf (response->str + 8, "%d,%d", &a, &b)) { + MMModemGsmAllowedMode mode = MM_MODEM_GSM_ALLOWED_MODE_ANY; + + switch (a) { + case 0: + mode = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY; + break; + case 1: + mode = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY; + break; + case 2: + mode = MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED; + break; + case 3: + mode = MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED; + break; + default: + break; + } + + mm_callback_info_set_result (info, GUINT_TO_POINTER (mode), NULL); + parsed = TRUE; + } + } + + if (!error && !parsed) + info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Could not parse allowed mode results"); + + mm_callback_info_schedule (info); +} + +void +mm_modem_icera_get_allowed_mode (MMModemIcera *self, + MMModemUIntFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + MMAtSerialPort *port; + + info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data); + + port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error); + if (!port) { + mm_callback_info_schedule (info); + return; + } + mm_at_serial_port_queue_command (port, "%IPSYS?", 3, get_allowed_mode_done, info); +} + +static void +set_allowed_mode_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (error) + info->error = g_error_copy (error); + + mm_callback_info_schedule (info); +} + +void +mm_modem_icera_set_allowed_mode (MMModemIcera *self, + MMModemGsmAllowedMode mode, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + MMAtSerialPort *port; + char *command; + int i; + + info = mm_callback_info_new (MM_MODEM (self), callback, user_data); + + port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error); + if (!port) { + mm_callback_info_schedule (info); + return; + } + + switch (mode) { + case MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY: + i = 0; + break; + case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY: + i = 1; + break; + case MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED: + i = 2; + break; + case MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED: + i = 3; + break; + case MM_MODEM_GSM_ALLOWED_MODE_ANY: + default: + i = 5; + break; + } + + command = g_strdup_printf ("%%IPSYS=%d", i); + mm_at_serial_port_queue_command (port, command, 3, set_allowed_mode_done, info); + g_free (command); +} + +static MMModemGsmAccessTech +nwstate_to_act (const char *str) +{ + /* small 'g' means CS, big 'G' means PS */ + if (!strcmp (str, "2G-GPRS")) + return MM_MODEM_GSM_ACCESS_TECH_GPRS; + else if (!strcmp (str, "2G-EDGE")) + return MM_MODEM_GSM_ACCESS_TECH_EDGE; + else if (!strcmp (str, "3G")) + return MM_MODEM_GSM_ACCESS_TECH_UMTS; + else if (!strcmp (str, "3G-HSDPA")) + return MM_MODEM_GSM_ACCESS_TECH_HSDPA; + else if (!strcmp (str, "3G-HSUPA")) + return MM_MODEM_GSM_ACCESS_TECH_HSUPA; + else if (!strcmp (str, "3G-HSDPA-HSUPA")) + return MM_MODEM_GSM_ACCESS_TECH_HSPA; + + return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; +} + +static void +nwstate_changed (MMAtSerialPort *port, + GMatchInfo *info, + gpointer user_data) +{ + MMModemIcera *self = MM_MODEM_ICERA (user_data); + MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; + char *str; + int rssi = -1; + + str = g_match_info_fetch (info, 1); + if (str) { + rssi = atoi (str); + rssi = CLAMP (rssi, -1, 5); + g_free (str); + } + + str = g_match_info_fetch (info, 3); + if (str) { + act = nwstate_to_act (str); + g_free (str); + } + + MM_MODEM_ICERA_GET_PRIVATE (self)->last_act = act; + mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (self), act); +} + +static void +pacsp_received (MMAtSerialPort *port, + GMatchInfo *info, + gpointer user_data) +{ + return; +} + +static void +get_nwstate_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + + info->error = mm_modem_check_removed (info->modem, error); + if (!info->error) { + MMModemIcera *self = MM_MODEM_ICERA (info->modem); + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + + /* The unsolicited message handler will already have run and + * removed the NWSTATE response, so we have to work around that. + */ + mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->last_act), NULL); + priv->last_act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN; + } + + mm_callback_info_schedule (info); +} + +void +mm_modem_icera_get_access_technology (MMModemIcera *self, + MMModemUIntFn callback, + gpointer user_data) +{ + MMAtSerialPort *port; + MMCallbackInfo *info; + + info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data); + + port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error); + if (!port) { + mm_callback_info_schedule (info); + return; + } + + mm_at_serial_port_queue_command (port, "%NWSTATE=1", 3, get_nwstate_done, info); +} + +/****************************************************************/ + +static void +disconnect_ipdpact_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + mm_callback_info_schedule ((MMCallbackInfo *) user_data); +} + +void +mm_modem_icera_do_disconnect (MMGenericGsm *gsm, + gint cid, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + MMAtSerialPort *primary; + char *command; + + info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data); + + primary = mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + command = g_strdup_printf ("%%IPDPACT=%d,0", cid); + mm_at_serial_port_queue_command (primary, command, 3, disconnect_ipdpact_done, info); + g_free (command); +} + +/*****************************************************************************/ + +static void +connect_pending_done (MMModemIcera *self) +{ + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + GError *error = NULL; + + if (priv->connect_pending_data) { + if (priv->connect_pending_data->error) { + error = priv->connect_pending_data->error; + priv->connect_pending_data->error = NULL; + } + + /* Complete the connect */ + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (self), error, priv->connect_pending_data); + priv->connect_pending_data = NULL; + } + + if (priv->connect_pending_id) { + g_source_remove (priv->connect_pending_id); + priv->connect_pending_id = 0; + } +} + +static void +icera_disconnect_done (MMModem *modem, + GError *error, + gpointer user_data) +{ + mm_info ("Modem signaled disconnection from the network"); +} + +static void +connection_enabled (MMAtSerialPort *port, + GMatchInfo *match_info, + gpointer user_data) +{ + MMModemIcera *self = MM_MODEM_ICERA (user_data); + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + MMCallbackInfo *info = priv->connect_pending_data; + char *str; + int status, cid, tmp; + + cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)); + if (cid < 0) + return; + + str = g_match_info_fetch (match_info, 1); + g_return_if_fail (str != NULL); + tmp = atoi (str); + g_free (str); + + /* Make sure the unsolicited message's CID matches the current CID */ + if (tmp != cid) + return; + + str = g_match_info_fetch (match_info, 2); + g_return_if_fail (str != NULL); + status = atoi (str); + g_free (str); + + switch (status) { + case 0: + /* Disconnected */ + if (mm_modem_get_state (MM_MODEM (self)) >= MM_MODEM_STATE_CONNECTED) + mm_modem_disconnect (MM_MODEM (self), icera_disconnect_done, NULL); + break; + case 1: + /* Connected */ + connect_pending_done (self); + break; + case 2: + /* Connecting */ + break; + case 3: + /* Call setup failure? */ + if (info) { + info->error = g_error_new_literal (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "Call setup failed"); + } + connect_pending_done (self); + break; + default: + mm_warn ("Unknown Icera connect status %d", status); + break; + } +} + +/****************************************************************/ + +static gint +_get_cid (MMModemIcera *self) +{ + gint cid; + + cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)); + if (cid < 0) { + g_warn_if_fail (cid >= 0); + cid = 0; + } + return cid; +} + +static void +icera_call_control (MMModemIcera *self, + gboolean activate, + MMAtSerialResponseFn callback, + gpointer user_data) +{ + char *command; + MMAtSerialPort *primary; + + primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + command = g_strdup_printf ("%%IPDPACT=%d,%d", _get_cid (self), activate ? 1 : 0); + mm_at_serial_port_queue_command (primary, command, 3, callback, user_data); + g_free (command); +} + +static void +timeout_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + connect_pending_done (MM_MODEM_ICERA (user_data)); +} + +static gboolean +icera_connect_timed_out (gpointer data) +{ + MMModemIcera *self = MM_MODEM_ICERA (data); + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + MMCallbackInfo *info = priv->connect_pending_data; + + priv->connect_pending_id = 0; + + if (info) { + info->error = g_error_new_literal (MM_SERIAL_ERROR, + MM_SERIAL_ERROR_RESPONSE_TIMEOUT, + "Connection timed out"); + } + + icera_call_control (self, FALSE, timeout_done, self); + return FALSE; +} + +static void +icera_enabled (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (error) { + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), error, info); + } else { + MMModemIcera *self = MM_MODEM_ICERA (info->modem); + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + + g_warn_if_fail (priv->connect_pending_id == 0); + if (priv->connect_pending_id) + g_source_remove (priv->connect_pending_id); + + priv->connect_pending_data = info; + priv->connect_pending_id = g_timeout_add_seconds (30, icera_connect_timed_out, self); + } +} + +static void +old_context_clear_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + /* Activate the PDP context and start the data session */ + icera_call_control (MM_MODEM_ICERA (info->modem), TRUE, icera_enabled, info); +} + +static void +auth_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (error) + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), error, info); + else { + /* Ensure the PDP context is deactivated */ + icera_call_control (MM_MODEM_ICERA (info->modem), FALSE, old_context_clear_done, info); + } +} + +void +mm_modem_icera_do_connect (MMModemIcera *self, + const char *number, + MMModemFn callback, + gpointer user_data) +{ + MMModem *modem = MM_MODEM (self); + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + MMCallbackInfo *info; + MMAtSerialPort *primary; + gint cid; + char *command; + + mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE); + + info = mm_callback_info_new (modem, callback, user_data); + + primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + cid = _get_cid (self); + + + /* Both user and password are required; otherwise firmware returns an error */ + if (!priv->username || !priv->password) + command = g_strdup_printf ("%%IPDPCFG=%d,0,0,\"\",\"\"", cid); + else { + command = g_strdup_printf ("%%IPDPCFG=%d,0,1,\"%s\",\"%s\"", + cid, + priv->password ? priv->password : "", + priv->username ? priv->username : ""); + + } + + mm_at_serial_port_queue_command (primary, command, 3, auth_done, info); + g_free (command); +} + +/****************************************************************/ + + +static void +free_dns_array (gpointer data) +{ + g_array_free ((GArray *) data, TRUE); +} + +static void +ip4_config_invoke (MMCallbackInfo *info) +{ + MMModemIp4Fn callback = (MMModemIp4Fn) info->callback; + + callback (info->modem, + GPOINTER_TO_UINT (mm_callback_info_get_data (info, "ip4-address")), + (GArray *) mm_callback_info_get_data (info, "ip4-dns"), + info->error, info->user_data); +} + +#define IPDPADDR_TAG "%IPDPADDR: " + +static void +get_ip4_config_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + char **items, **iter; + GArray *dns_array; + int i; + guint32 tmp; + gint cid; + + if (error) { + info->error = g_error_copy (error); + goto out; + } else if (!g_str_has_prefix (response->str, IPDPADDR_TAG)) { + info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Retrieving failed: invalid response."); + goto out; + } + + cid = _get_cid (MM_MODEM_ICERA (info->modem)); + dns_array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 2); + + /* %IPDPADDR: <cid>,<ip>,<gw>,<dns1>,<dns2>[,<nbns1>,<nbns2>] */ + items = g_strsplit (response->str + strlen (IPDPADDR_TAG), ", ", 0); + + for (iter = items, i = 0; *iter; iter++, i++) { + if (i == 0) { /* CID */ + long int num; + + errno = 0; + num = strtol (*iter, NULL, 10); + if (errno != 0 || num < 0 || (gint) num != cid) { + info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Unknown CID in IPDPADDR response (" + "got %d, expected %d)", (guint) num, cid); + break; + } + } else if (i == 1) { /* IP address */ + if (inet_pton (AF_INET, *iter, &tmp) > 0) + mm_callback_info_set_data (info, "ip4-address", GUINT_TO_POINTER (tmp), NULL); + } else if (i == 3) { /* DNS 1 */ + if (inet_pton (AF_INET, *iter, &tmp) > 0) + g_array_append_val (dns_array, tmp); + } else if (i == 4) { /* DNS 2 */ + if (inet_pton (AF_INET, *iter, &tmp) > 0) + g_array_append_val (dns_array, tmp); + } + } + + g_strfreev (items); + mm_callback_info_set_data (info, "ip4-dns", dns_array, free_dns_array); + + out: + mm_callback_info_schedule (info); +} + +void +mm_modem_icera_get_ip4_config (MMModemIcera *self, + MMModemIp4Fn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + char *command; + MMAtSerialPort *primary; + + info = mm_callback_info_new_full (MM_MODEM (self), + ip4_config_invoke, + G_CALLBACK (callback), + user_data); + + primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + command = g_strdup_printf ("%%IPDPADDR=%d", _get_cid (self)); + mm_at_serial_port_queue_command (primary, command, 3, get_ip4_config_done, info); + g_free (command); +} + +/****************************************************************/ + +static const char * +get_string_property (GHashTable *properties, const char *name) +{ + GValue *value; + + value = (GValue *) g_hash_table_lookup (properties, name); + if (value && G_VALUE_HOLDS_STRING (value)) + return g_value_get_string (value); + return NULL; +} + +void +mm_modem_icera_simple_connect (MMModemIcera *self, GHashTable *properties) +{ + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + + g_free (priv->username); + priv->username = g_strdup (get_string_property (properties, "username")); + g_free (priv->password); + priv->password = g_strdup (get_string_property (properties, "password")); +} + +/****************************************************************/ + +void +mm_modem_icera_register_unsolicted_handlers (MMModemIcera *self, + MMAtSerialPort *port) +{ + GRegex *regex; + + /* %NWSTATE: <rssi>,<mccmnc>,<tech>,<connected>,<regulation> */ + regex = g_regex_new ("\\r\\n%NWSTATE:\\s*(\\d+),(\\d+),([^,]*),([^,]*),(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + mm_at_serial_port_add_unsolicited_msg_handler (port, regex, nwstate_changed, self, NULL); + g_regex_unref (regex); + + regex = g_regex_new ("\\r\\n\\+PACSP(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + mm_at_serial_port_add_unsolicited_msg_handler (port, regex, pacsp_received, self, NULL); + g_regex_unref (regex); + + /* %IPDPACT: <cid>,<status>,0 */ + regex = g_regex_new ("\\r\\n%IPDPACT:\\s*(\\d+),\\s*(\\d+),\\s*(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + mm_at_serial_port_add_unsolicited_msg_handler (port, regex, connection_enabled, self, NULL); + g_regex_unref (regex); +} + +void +mm_modem_icera_change_unsolicited_messages (MMModemIcera *self, gboolean enabled) +{ + MMAtSerialPort *primary; + + primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + mm_at_serial_port_queue_command (primary, enabled ? "%NWSTATE=1" : "%NWSTATE=0", 3, NULL, NULL); +} + +/****************************************************************/ + +static void +is_icera_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = user_data; + + info->error = mm_modem_check_removed (info->modem, error); + if (!info->error) + mm_callback_info_set_result (info, GUINT_TO_POINTER (TRUE), NULL); + mm_callback_info_schedule (info); +} + +void +mm_modem_icera_is_icera (MMModemIcera *self, + MMModemUIntFn callback, + gpointer user_data) +{ + MMAtSerialPort *port; + MMCallbackInfo *info; + + info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data); + + port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error); + if (!port) { + mm_callback_info_schedule (info); + return; + } + + mm_at_serial_port_queue_command (port, "%IPSYS?", 5, is_icera_done, info); +} + +/****************************************************************/ + +void +mm_modem_icera_prepare (MMModemIcera *self) +{ + self->priv = g_malloc0 (sizeof (MMModemIceraPrivate)); +} + +void +mm_modem_icera_cleanup (MMModemIcera *self) +{ + MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self); + + /* Clear the pending connection if necessary */ + connect_pending_done (self); + + g_free (priv->username); + g_free (priv->password); + + memset (priv, 0, sizeof (MMModemIceraPrivate)); + g_free (priv); +} + +static void +mm_modem_icera_init (gpointer g_iface) +{ + static gboolean initialized = FALSE; + + if (!initialized) { + initialized = TRUE; + } +} + +GType +mm_modem_icera_get_type (void) +{ + static GType icera_type = 0; + + if (!G_UNLIKELY (icera_type)) { + const GTypeInfo icera_info = { + sizeof (MMModemIcera), /* class_size */ + mm_modem_icera_init, /* base_init */ + NULL, /* base_finalize */ + NULL, + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL + }; + + icera_type = g_type_register_static (G_TYPE_INTERFACE, + "MMModemIcera", + &icera_info, 0); + + g_type_interface_add_prerequisite (icera_type, MM_TYPE_MODEM); + } + + return icera_type; +} + diff --git a/plugins/mm-modem-icera.h b/plugins/mm-modem-icera.h new file mode 100644 index 00000000..71258d2a --- /dev/null +++ b/plugins/mm-modem-icera.h @@ -0,0 +1,89 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details: + * + * Copyright (C) 2010 Red Hat, Inc. + */ + +/****************************************** + * Generic utilities for Icera-based modems + ******************************************/ + +#ifndef MM_MODEM_ICERA_H +#define MM_MODEM_ICERA_H + +#include <glib-object.h> + +#include "mm-modem-gsm.h" +#include "mm-generic-gsm.h" + +#define MM_TYPE_MODEM_ICERA (mm_modem_icera_get_type ()) +#define MM_MODEM_ICERA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_ICERA, MMModemIcera)) +#define MM_IS_MODEM_ICERA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_ICERA)) +#define MM_MODEM_ICERA_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_MODEM_ICERA, MMModemIcera)) + +typedef struct _MMModemIceraPrivate MMModemIceraPrivate; + +typedef struct _MMModemIcera MMModemIcera; + +struct _MMModemIcera { + GTypeInterface g_iface; + + MMModemIceraPrivate *priv; +}; + +GType mm_modem_icera_get_type (void); + +void mm_modem_icera_prepare (MMModemIcera *self); + +void mm_modem_icera_cleanup (MMModemIcera *self); + +void mm_modem_icera_get_allowed_mode (MMModemIcera *self, + MMModemUIntFn callback, + gpointer user_data); + +void mm_modem_icera_set_allowed_mode (MMModemIcera *self, + MMModemGsmAllowedMode mode, + MMModemFn callback, + gpointer user_data); + +void mm_modem_icera_register_unsolicted_handlers (MMModemIcera *self, + MMAtSerialPort *port); + +void mm_modem_icera_change_unsolicited_messages (MMModemIcera *self, + gboolean enabled); + +void mm_modem_icera_get_access_technology (MMModemIcera *self, + MMModemUIntFn callback, + gpointer user_data); + +void mm_modem_icera_is_icera (MMModemIcera *self, + MMModemUIntFn callback, + gpointer user_data); + +void mm_modem_icera_do_disconnect (MMGenericGsm *gsm, + gint cid, + MMModemFn callback, + gpointer user_data); + +void mm_modem_icera_simple_connect (MMModemIcera *self, GHashTable *properties); + +void mm_modem_icera_do_connect (MMModemIcera *self, + const char *number, + MMModemFn callback, + gpointer user_data); + +void mm_modem_icera_get_ip4_config (MMModemIcera *self, + MMModemIp4Fn callback, + gpointer user_data); + +#endif /* MM_MODEM_ICERA_H */ + diff --git a/plugins/mm-modem-mbm.c b/plugins/mm-modem-mbm.c index 53e98ba6..93034537 100644 --- a/plugins/mm-modem-mbm.c +++ b/plugins/mm-modem-mbm.c @@ -1,7 +1,7 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * Copyright (C) 2008 - 2010 Ericsson AB - * Copyright (C) 2009 - 2010 Red Hat, Inc. + * Copyright (C) 2009 - 2011 Red Hat, Inc. * * Author: Per Hallsmark <per.hallsmark@ericsson.com> * Bjorn Runaker <bjorn.runaker@ericsson.com> @@ -31,6 +31,7 @@ #include "mm-modem-gsm-card.h" #include "mm-errors.h" #include "mm-callback-info.h" +#include "mm-log.h" static void modem_init (MMModem *modem_class); static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class); @@ -410,7 +411,7 @@ mbm_emrdy_done (MMAtSerialPort *port, MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (info->modem); if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) - g_warning ("%s: timed out waiting for EMRDY response.", __func__); + mm_warn ("timed out waiting for EMRDY response."); else priv->have_emrdy = TRUE; @@ -510,6 +511,24 @@ do_disconnect (MMGenericGsm *gsm, } static void +reset (MMModem *modem, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + MMAtSerialPort *port; + + info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); + + /* Ensure we have a usable port to use for the command */ + port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error); + if (port) + mm_at_serial_port_queue_command (port, "*E2RESET", 3, NULL, NULL); + + mm_callback_info_schedule (info); +} + +static void factory_reset_done (MMAtSerialPort *port, GString *response, GError *error, @@ -614,16 +633,16 @@ mbm_e2nap_received (MMAtSerialPort *port, g_free (str); if (MBM_E2NAP_DISCONNECTED == state) { - g_debug ("%s: disconnected", __func__); + mm_dbg ("disconnected"); mbm_do_connect_done (MM_MODEM_MBM (user_data), FALSE); } else if (MBM_E2NAP_CONNECTED == state) { - g_debug ("%s: connected", __func__); + mm_dbg ("connected"); mbm_do_connect_done (MM_MODEM_MBM (user_data), TRUE); } else if (MBM_E2NAP_CONNECTING == state) - g_debug("%s: connecting", __func__); + mm_dbg ("connecting"); else { /* Should not happen */ - g_debug("%s: unhandled E2NAP state %d", __func__, state); + mm_dbg ("unhandled E2NAP state %d", state); mbm_do_connect_done (MM_MODEM_MBM (user_data), FALSE); } } @@ -793,7 +812,7 @@ send_epin_done (MMAtSerialPort *port, else if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PUK2)) sscanf (response->str, "*EPIN: %*d, %*d, %*d, %d", &attempts_left); else { - g_debug ("%s: unhandled pin type '%s'", __func__, pin_type); + mm_dbg ("unhandled pin type '%s'", pin_type); info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Unhandled PIN type"); } @@ -820,7 +839,7 @@ mbm_get_unlock_retries (MMModemGsmCard *modem, char *command; MMCallbackInfo *info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); - g_debug ("%s: pin type '%s'", __func__, pin_type); + mm_dbg ("pin type '%s'", pin_type); /* Ensure we have a usable port to use for the command */ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error); @@ -940,6 +959,7 @@ modem_init (MMModem *modem_class) modem_class->grab_port = grab_port; modem_class->disable = disable; modem_class->connect = do_connect; + modem_class->reset = reset; modem_class->factory_reset = factory_reset; } diff --git a/plugins/mm-modem-zte.c b/plugins/mm-modem-zte.c index 558260ec..c447c58f 100644 --- a/plugins/mm-modem-zte.c +++ b/plugins/mm-modem-zte.c @@ -24,11 +24,17 @@ #include "mm-errors.h" #include "mm-callback-info.h" #include "mm-modem-helpers.h" +#include "mm-modem-simple.h" +#include "mm-modem-icera.h" static void modem_init (MMModem *modem_class); +static void modem_icera_init (MMModemIcera *icera_class); +static void modem_simple_init (MMModemSimple *simple_class); G_DEFINE_TYPE_EXTENDED (MMModemZte, mm_modem_zte, MM_TYPE_GENERIC_GSM, 0, - G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)) + G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init) + G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_ICERA, modem_icera_init) + G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simple_init)) #define MM_MODEM_ZTE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_ZTE, MMModemZtePrivate)) @@ -36,6 +42,7 @@ typedef struct { gboolean init_retried; guint32 cpms_tries; guint cpms_timeout; + gboolean is_icera; } MMModemZtePrivate; MMModem * @@ -149,9 +156,15 @@ get_allowed_mode (MMGenericGsm *gsm, MMModemUIntFn callback, gpointer user_data) { + MMModemZte *self = MM_MODEM_ZTE (gsm); MMCallbackInfo *info; MMAtSerialPort *port; + if (MM_MODEM_ZTE_GET_PRIVATE (self)->is_icera) { + mm_modem_icera_get_allowed_mode (MM_MODEM_ICERA (self), callback, user_data); + return; + } + info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data); port = mm_generic_gsm_get_best_at_port (gsm, &info->error); @@ -183,11 +196,17 @@ set_allowed_mode (MMGenericGsm *gsm, MMModemFn callback, gpointer user_data) { + MMModemZte *self = MM_MODEM_ZTE (gsm); MMCallbackInfo *info; MMAtSerialPort *port; char *command; int cm_mode = 0, pref_acq = 0; + if (MM_MODEM_ZTE_GET_PRIVATE (self)->is_icera) { + mm_modem_icera_set_allowed_mode (MM_MODEM_ICERA (self), mode, callback, user_data); + return; + } + info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data); port = mm_generic_gsm_get_best_at_port (gsm, &info->error); @@ -248,16 +267,22 @@ get_act_request_done (MMAtSerialPort *port, } static void -get_access_technology (MMGenericGsm *modem, +get_access_technology (MMGenericGsm *gsm, MMModemUIntFn callback, gpointer user_data) { + MMModemZte *self = MM_MODEM_ZTE (gsm); MMAtSerialPort *port; MMCallbackInfo *info; - info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data); + if (MM_MODEM_ZTE_GET_PRIVATE (self)->is_icera) { + mm_modem_icera_get_access_technology (MM_MODEM_ICERA (self), callback, user_data); + return; + } - port = mm_generic_gsm_get_best_at_port (modem, &info->error); + info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data); + + port = mm_generic_gsm_get_best_at_port (gsm, &info->error); if (!port) { mm_callback_info_schedule (info); return; @@ -266,6 +291,21 @@ get_access_technology (MMGenericGsm *modem, mm_at_serial_port_queue_command (port, "+ZPAS?", 3, get_act_request_done, info); } +static void +do_disconnect (MMGenericGsm *gsm, + gint cid, + MMModemFn callback, + gpointer user_data) +{ + MMModemZte *self = MM_MODEM_ZTE (gsm); + MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (self); + + if (priv->is_icera) + mm_modem_icera_do_disconnect (gsm, cid, callback, user_data); + else + MM_GENERIC_GSM_CLASS (mm_modem_zte_parent_class)->do_disconnect (gsm, cid, callback, user_data); +} + /*****************************************************************************/ /* Modem class override functions */ /*****************************************************************************/ @@ -314,6 +354,10 @@ cpms_try_done (MMAtSerialPort *port, } } + /* Turn on unsolicited network state messages */ + if (priv->is_icera) + mm_modem_icera_change_unsolicited_messages (MM_MODEM_ICERA (info->modem), TRUE); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); } @@ -325,6 +369,8 @@ init_modem_done (MMAtSerialPort *port, { MMCallbackInfo *info = (MMCallbackInfo *) user_data; + mm_at_serial_port_queue_command (port, "E0", 5, NULL, NULL); + /* Attempt to disable floods of "+ZUSIMR:2" unsolicited responses that * eventually fill up the device's buffers and make it crash. Normally * done during probing, but if the device has a PIN enabled it won't @@ -338,13 +384,33 @@ static void enable_flash_done (MMSerialPort *port, gpointer user_data); static void +icera_check_cb (MMModem *modem, + guint32 result, + GError *error, + gpointer user_data) +{ + if (!error) { + MMModemZte *self = MM_MODEM_ZTE (user_data); + MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (self); + + if (result) { + priv->is_icera = TRUE; + g_object_set (G_OBJECT (modem), + MM_MODEM_IP_METHOD, MM_MODEM_IP_METHOD_STATIC, + NULL); + } + } +} + +static void pre_init_done (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (info->modem); + MMModemZte *self = MM_MODEM_ZTE (info->modem); + MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (self); if (error) { /* Retry the init string one more time; the modem sometimes throws it away */ @@ -353,9 +419,10 @@ pre_init_done (MMAtSerialPort *port, priv->init_retried = TRUE; enable_flash_done (MM_SERIAL_PORT (port), NULL, user_data); } else - mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (self), error, info); } else { /* Finish the initialization */ + mm_modem_icera_is_icera (MM_MODEM_ICERA (self), icera_check_cb, self); mm_at_serial_port_queue_command (port, "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1;", 10, init_modem_done, info); } } @@ -387,21 +454,112 @@ do_enable (MMGenericGsm *modem, MMModemFn callback, gpointer user_data) mm_serial_port_flash (MM_SERIAL_PORT (primary), 100, FALSE, enable_flash_done, info); } +/*****************************************************************************/ + +typedef struct { + MMModem *modem; + MMModemFn callback; + gpointer user_data; +} DisableInfo; + +static void +disable_unsolicited_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) + +{ + MMModem *parent_modem_iface; + DisableInfo *info = user_data; + + parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (info->modem)); + parent_modem_iface->disable (info->modem, info->callback, info->user_data); + g_free (info); +} + static void disable (MMModem *modem, MMModemFn callback, gpointer user_data) { MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (modem); - MMModem *parent_modem_iface; + MMAtSerialPort *primary; + DisableInfo *info; priv->init_retried = FALSE; - /* Do the normal disable stuff */ - parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem)); - parent_modem_iface->disable (modem, callback, user_data); + info = g_malloc0 (sizeof (DisableInfo)); + info->callback = callback; + info->user_data = user_data; + info->modem = modem; + + primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + /* Turn off unsolicited responses */ + if (priv->is_icera) { + mm_modem_icera_cleanup (MM_MODEM_ICERA (modem)); + mm_modem_icera_change_unsolicited_messages (MM_MODEM_ICERA (modem), FALSE); + } + + /* Random command to ensure unsolicited message disable completes */ + mm_at_serial_port_queue_command (primary, "E0", 5, disable_unsolicited_done, info); +} + +/*****************************************************************************/ + +static void +do_connect (MMModem *modem, + const char *number, + MMModemFn callback, + gpointer user_data) +{ + MMModem *parent_iface; + + if (MM_MODEM_ZTE_GET_PRIVATE (modem)->is_icera) + mm_modem_icera_do_connect (MM_MODEM_ICERA (modem), number, callback, user_data); + else { + parent_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem)); + parent_iface->connect (MM_MODEM (modem), number, callback, user_data); + } +} + +static void +get_ip4_config (MMModem *modem, + MMModemIp4Fn callback, + gpointer user_data) +{ + MMModem *parent_iface; + + if (MM_MODEM_ZTE_GET_PRIVATE (modem)->is_icera) { + mm_modem_icera_get_ip4_config (MM_MODEM_ICERA (modem), callback, user_data); + } else { + parent_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem)); + parent_iface->get_ip4_config (MM_MODEM (modem), callback, user_data); + } +} + +/*****************************************************************************/ + +static void +simple_connect (MMModemSimple *simple, + GHashTable *properties, + MMModemFn callback, + gpointer user_data) +{ + MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (simple); + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMModemSimple *parent_iface; + + if (priv->is_icera) + mm_modem_icera_simple_connect (MM_MODEM_ICERA (simple), properties); + + parent_iface = g_type_interface_peek_parent (MM_MODEM_SIMPLE_GET_INTERFACE (simple)); + parent_iface->connect (MM_MODEM_SIMPLE (simple), properties, callback, info); } +/*****************************************************************************/ + static gboolean grab_port (MMModem *modem, const char *subsys, @@ -451,6 +609,9 @@ grab_port (MMModem *modem, regex = g_regex_new ("\\r\\n\\+ZEND\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL); g_regex_unref (regex); + + /* Add Icera-specific handlers */ + mm_modem_icera_register_unsolicted_handlers (MM_MODEM_ICERA (gsm), MM_AT_SERIAL_PORT (port)); } return !!port; @@ -462,10 +623,24 @@ static void modem_init (MMModem *modem_class) { modem_class->disable = disable; + modem_class->connect = do_connect; + modem_class->get_ip4_config = get_ip4_config; modem_class->grab_port = grab_port; } static void +modem_icera_init (MMModemIcera *icera_class) +{ + mm_modem_icera_prepare (icera_class); +} + +static void +modem_simple_init (MMModemSimple *class) +{ + class->connect = simple_connect; +} + +static void mm_modem_zte_init (MMModemZte *self) { } @@ -478,6 +653,10 @@ dispose (GObject *object) if (priv->cpms_timeout) g_source_remove (priv->cpms_timeout); + + mm_modem_icera_cleanup (MM_MODEM_ICERA (self)); + + G_OBJECT_CLASS (mm_modem_zte_parent_class)->dispose (object); } static void @@ -491,6 +670,7 @@ mm_modem_zte_class_init (MMModemZteClass *klass) object_class->dispose = dispose; gsm_class->do_enable = do_enable; + gsm_class->do_disconnect = do_disconnect; gsm_class->set_allowed_mode = set_allowed_mode; gsm_class->get_allowed_mode = get_allowed_mode; gsm_class->get_access_technology = get_access_technology; diff --git a/plugins/mm-plugin-generic.c b/plugins/mm-plugin-generic.c index 9704ae84..a27704b4 100644 --- a/plugins/mm-plugin-generic.c +++ b/plugins/mm-plugin-generic.c @@ -31,6 +31,7 @@ #include "mm-generic-cdma.h" #include "mm-errors.h" #include "mm-serial-parsers.h" +#include "mm-log.h" G_DEFINE_TYPE (MMPluginGeneric, mm_plugin_generic, MM_TYPE_PLUGIN_BASE) @@ -127,10 +128,10 @@ grab_port (MMPluginBase *base, g_set_error (error, 0, 0, "Could not get port's sysfs file."); return NULL; } else { - g_message ("%s: (%s/%s) WARNING: missing udev 'device' file", - mm_plugin_get_name (MM_PLUGIN (base)), - subsys, - name); + mm_warn ("%s: (%s/%s) WARNING: missing udev 'device' file", + mm_plugin_get_name (MM_PLUGIN (base)), + subsys, + name); } } diff --git a/plugins/mm-plugin-huawei.c b/plugins/mm-plugin-huawei.c index 090bb0d5..f1590ca3 100644 --- a/plugins/mm-plugin-huawei.c +++ b/plugins/mm-plugin-huawei.c @@ -27,6 +27,7 @@ #include "mm-modem-huawei-cdma.h" #include "mm-serial-parsers.h" #include "mm-at-serial-port.h" +#include "mm-log.h" G_DEFINE_TYPE (MMPluginHuawei, mm_plugin_huawei, MM_TYPE_PLUGIN_BASE) @@ -240,10 +241,10 @@ supports_port (MMPluginBase *base, info->id = g_timeout_add_seconds (7, probe_secondary_timeout, task); if (!mm_serial_port_open (MM_SERIAL_PORT (info->serial), &error)) { - g_warning ("%s: (Huawei) %s: couldn't open serial port: (%d) %s", - __func__, name, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); + mm_warn ("(Huawei) %s: couldn't open serial port: (%d) %s", + name, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); g_clear_error (&error); huawei_supports_info_destroy (info); return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; diff --git a/plugins/mm-plugin-mbm.c b/plugins/mm-plugin-mbm.c index dd64cc66..6684ff9a 100644 --- a/plugins/mm-plugin-mbm.c +++ b/plugins/mm-plugin-mbm.c @@ -84,7 +84,7 @@ supports_port (MMPluginBase *base, client = g_udev_client_new (sys); if (!client) { - g_warning ("mbm: could not get udev client."); + g_warn_if_fail (client != NULL); return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; } diff --git a/plugins/mm-plugin-zte.c b/plugins/mm-plugin-zte.c index 97bbcc36..bb2ee176 100644 --- a/plugins/mm-plugin-zte.c +++ b/plugins/mm-plugin-zte.c @@ -11,7 +11,7 @@ * GNU General Public License for more details: * * Copyright (C) 2008 - 2009 Novell, Inc. - * Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2009 - 2010 Red Hat, Inc. */ #include <string.h> @@ -73,9 +73,6 @@ supports_port (MMPluginBase *base, /* Can't do anything with non-serial ports */ port = mm_plugin_base_supports_task_get_port (task); - if (strcmp (g_udev_device_get_subsystem (port), "tty")) - return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; - subsys = g_udev_device_get_subsystem (port); name = g_udev_device_get_name (port); @@ -85,6 +82,20 @@ supports_port (MMPluginBase *base, if (vendor != 0x19d2) return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; + if (!strcmp (subsys, "net")) { + /* If we don't know the modem's type yet, defer grabbing the port + * until we know the type. + */ + if (!existing) + return MM_PLUGIN_SUPPORTS_PORT_DEFER; + + mm_plugin_base_supports_task_complete (task, 10); + return MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS; + } + + if (strcmp (subsys, "tty")) + return MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED; + if (mm_plugin_base_get_cached_port_capabilities (base, port, &cached)) { level = get_level_for_capabilities (cached); if (level) { @@ -165,7 +176,7 @@ grab_port (MMPluginBase *base, return NULL; } } - } else if (get_level_for_capabilities (caps)) { + } else if (get_level_for_capabilities (caps) || (!strcmp (subsys, "net"))) { if (caps & MM_PLUGIN_BASE_PORT_CAP_QCDM) ptype = MM_PORT_TYPE_QCDM; diff --git a/src/77-mm-usb-device-blacklist.rules b/src/77-mm-usb-device-blacklist.rules index 78a6770d..58b0cee6 100644 --- a/src/77-mm-usb-device-blacklist.rules +++ b/src/77-mm-usb-device-blacklist.rules @@ -62,5 +62,11 @@ ATTRS{idVendor}=="0592", ATTRS{idProduct}=="0002", ENV{ID_MM_DEVICE_IGNORE}="1" # that isn't blacklisted. ATTRS{idVendor}=="0830", ATTRS{idProduct}=="0061", ENV{ID_MM_DEVICE_IGNORE}="1" +# Belkin F5U183 Serial Adapter (unlikely to have a modem behind it) +ATTRS{idVendor}=="050d", ATTRS{idProduct}=="0103", ENV{ID_MM_DEVICE_IGNORE}="1" + +# ATEN Intl UC-232A (Prolific) +ATTRS{idVendor}=="0557", ATTRS{idProduct}=="2008", ENV{ID_MM_DEVICE_IGNORE}="1" + LABEL="mm_usb_device_blacklist_end" diff --git a/src/Makefile.am b/src/Makefile.am index 3e656d81..e813e7e8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -81,6 +81,8 @@ endif modem_manager_SOURCES = \ main.c \ + mm-log.c \ + mm-log.h \ mm-callback-info.c \ mm-callback-info.h \ $(auth_sources) \ @@ -109,8 +111,6 @@ modem_manager_SOURCES = \ mm-modem-gsm-ussd.h \ mm-modem-simple.c \ mm-modem-simple.h \ - mm-options.c \ - mm-options.h \ mm-plugin.c \ mm-plugin.h \ mm-plugin-base.c \ @@ -11,7 +11,7 @@ * GNU General Public License for more details: * * Copyright (C) 2008 - 2009 Novell, Inc. - * Copyright (C) 2009 - 2010 Red Hat, Inc. + * Copyright (C) 2009 - 2011 Red Hat, Inc. */ #include <config.h> @@ -21,8 +21,10 @@ #include <unistd.h> #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> +#include <stdlib.h> + #include "mm-manager.h" -#include "mm-options.h" +#include "mm-log.h" #if !defined(MM_DIST_VERSION) # define MM_DIST_VERSION VERSION @@ -34,9 +36,9 @@ static void mm_signal_handler (int signo) { if (signo == SIGUSR1) - mm_options_set_debug (!mm_options_debug ()); + mm_log_usr1 (); else if (signo == SIGINT || signo == SIGTERM) { - g_message ("Caught signal %d, shutting down...", signo); + mm_info ("Caught signal %d, shutting down...", signo); if (loop) g_main_loop_quit (loop); else @@ -60,64 +62,9 @@ setup_signals (void) } static void -log_handler (const gchar *log_domain, - GLogLevelFlags log_level, - const gchar *message, - gpointer ignored) -{ - int syslog_priority; - - switch (log_level) { - case G_LOG_LEVEL_ERROR: - syslog_priority = LOG_CRIT; - break; - - case G_LOG_LEVEL_CRITICAL: - syslog_priority = LOG_ERR; - break; - - case G_LOG_LEVEL_WARNING: - syslog_priority = LOG_WARNING; - break; - - case G_LOG_LEVEL_MESSAGE: - syslog_priority = LOG_NOTICE; - break; - - case G_LOG_LEVEL_DEBUG: - syslog_priority = LOG_DEBUG; - break; - - case G_LOG_LEVEL_INFO: - default: - syslog_priority = LOG_INFO; - break; - } - - syslog (syslog_priority, "%s", message); -} - - -static void -logging_setup (void) -{ - openlog (G_LOG_DOMAIN, LOG_CONS, LOG_DAEMON); - g_log_set_handler (G_LOG_DOMAIN, - G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, - log_handler, - NULL); -} - -static void -logging_shutdown (void) -{ - closelog (); -} - -static void destroy_cb (DBusGProxy *proxy, gpointer user_data) { - g_message ("disconnected from the system bus, exiting."); + mm_warn ("disconnected from the system bus, exiting."); g_main_loop_quit (loop); } @@ -139,16 +86,16 @@ create_dbus_proxy (DBusGConnection *bus) G_TYPE_INVALID, G_TYPE_UINT, &request_name_result, G_TYPE_INVALID)) { - g_warning ("Could not acquire the %s service.\n" - " Message: '%s'", MM_DBUS_SERVICE, err->message); + mm_warn ("Could not acquire the %s service.\n" + " Message: '%s'", MM_DBUS_SERVICE, err->message); g_error_free (err); g_object_unref (proxy); proxy = NULL; } else if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { - g_warning ("Could not acquire the " MM_DBUS_SERVICE - " service as it is already taken. Return: %d", - request_name_result); + mm_warn ("Could not acquire the " MM_DBUS_SERVICE + " service as it is already taken. Return: %d", + request_name_result); g_object_unref (proxy); proxy = NULL; @@ -175,17 +122,49 @@ main (int argc, char *argv[]) DBusGProxy *proxy; MMManager *manager; GError *err = NULL; + GOptionContext *opt_ctx; guint id; + const char *log_level = NULL, *log_file = NULL; + gboolean debug = FALSE, show_ts = FALSE, rel_ts = FALSE; + + GOptionEntry entries[] = { + { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Output to console rather than syslog", NULL }, + { "log-level", 0, 0, G_OPTION_ARG_STRING, &log_level, "Log level: one of [ERR, WARN, INFO, DEBUG]", "INFO" }, + { "log-file", 0, 0, G_OPTION_ARG_STRING, &log_file, "Path to log file", NULL }, + { "timestamps", 0, 0, G_OPTION_ARG_NONE, &show_ts, "Show timestamps in log output", NULL }, + { "relative-timestamps", 0, 0, G_OPTION_ARG_NONE, &rel_ts, "Use relative timestamps (from MM start)", NULL }, + { NULL } + }; - mm_options_parse (argc, argv); g_type_init (); - setup_signals (); + opt_ctx = g_option_context_new (NULL); + g_option_context_set_summary (opt_ctx, "DBus system service to communicate with modems."); + g_option_context_add_main_entries (opt_ctx, entries, NULL); + + if (!g_option_context_parse (opt_ctx, &argc, &argv, &err)) { + g_warning ("%s\n", err->message); + g_error_free (err); + exit (1); + } - if (!mm_options_debug ()) - logging_setup (); + g_option_context_free (opt_ctx); + + if (debug) { + log_level = "DEBUG"; + if (!show_ts && !rel_ts) + show_ts = TRUE; + } + + if (!mm_log_setup (log_level, log_file, show_ts, rel_ts, &err)) { + g_warning ("Failed to set up logging: %s", err->message); + g_error_free (err); + exit (1); + } + + setup_signals (); - g_message ("ModemManager (version " MM_DIST_VERSION ") starting..."); + mm_info ("ModemManager (version " MM_DIST_VERSION ") starting..."); bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err); if (!bus) { @@ -235,7 +214,7 @@ main (int argc, char *argv[]) g_object_unref (proxy); dbus_g_connection_unref (bus); - logging_shutdown (); + mm_log_shutdown (); return 0; } diff --git a/src/mm-at-serial-port.c b/src/mm-at-serial-port.c index 3df8681b..30da3a3b 100644 --- a/src/mm-at-serial-port.c +++ b/src/mm-at-serial-port.c @@ -23,7 +23,7 @@ #include "mm-at-serial-port.h" #include "mm-errors.h" -#include "mm-options.h" +#include "mm-log.h" G_DEFINE_TYPE (MMAtSerialPort, mm_at_serial_port, MM_TYPE_SERIAL_PORT) @@ -273,7 +273,6 @@ debug_log (MMSerialPort *port, const char *prefix, const char *buf, gsize len) { static GString *debug = NULL; const char *s; - GTimeVal tv; if (!debug) debug = g_string_sized_new (256); @@ -296,12 +295,7 @@ debug_log (MMSerialPort *port, const char *prefix, const char *buf, gsize len) } g_string_append_c (debug, '\''); - g_get_current_time (&tv); - g_debug ("<%ld.%ld> (%s): %s", - tv.tv_sec, - tv.tv_usec, - mm_port_get_device (MM_PORT (port)), - debug->str); + mm_dbg ("(%s): %s", mm_port_get_device (MM_PORT (port)), debug->str); g_string_truncate (debug, 0); } diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index f3e99d1a..0a95e7b1 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -30,6 +30,7 @@ #include "mm-serial-parsers.h" #include "mm-modem-helpers.h" #include "libqcdm/src/commands.h" +#include "mm-log.h" #define MM_GENERIC_CDMA_PREV_STATE_TAG "prev-state" @@ -68,6 +69,8 @@ typedef struct { guint poll_id; + char *meid; + MMModemCdmaRegistrationState cdma_1x_reg_state; MMModemCdmaRegistrationState evdo_reg_state; @@ -1045,7 +1048,7 @@ get_signal_quality (MMModemCdma *modem, at_port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (modem), &info->error); if (!at_port && !priv->qcdm) { - g_message ("Returning saved signal quality %d", priv->cdma1x_quality); + mm_dbg ("Returning saved signal quality %d", priv->cdma1x_quality); mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->cdma1x_quality), NULL); mm_callback_info_schedule (info); return; @@ -1524,15 +1527,22 @@ reg_query_speri_done (MMAtSerialPort *port, if (!p || !mm_cdma_parse_eri (p, &roam, NULL, NULL)) goto done; - /* Change the 1x and EVDO registration states to roaming if they were - * anything other than UNKNOWN. - */ if (roam) { + /* Change the 1x and EVDO registration states to roaming if they were + * anything other than UNKNOWN. + */ if (mm_generic_cdma_query_reg_state_get_callback_1x_state (info)) mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING); if (mm_generic_cdma_query_reg_state_get_callback_evdo_state (info)) mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING); + } else { + /* Change 1x and/or EVDO registration state to home if home/roaming wasn't previously known */ + if (mm_generic_cdma_query_reg_state_get_callback_1x_state (info) == MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED) + mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_HOME); + + if (mm_generic_cdma_query_reg_state_get_callback_evdo_state (info) == MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED) + mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_HOME); } done: @@ -1584,6 +1594,12 @@ real_query_registration_state (MMGenericCdma *self, port = mm_generic_cdma_get_best_at_port (self, &info->error); if (!port) { + /* If we can't get an AT port, but less specific registration checks + * were successful, just use that and don't return an error. + */ + if ( cur_cdma_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN + || cur_evdo_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) + g_clear_error (&info->error); mm_callback_info_schedule (info); return; } @@ -1722,7 +1738,7 @@ reg_hdrstate_cb (MMQcdmSerialPort *port, /* Get HDR subsystem state to determine EVDO registration when in 1X mode */ result = qcdm_cmd_hdr_subsys_state_info_result ((const char *) response->data, response->len, - &info->error); + NULL); if (result) { guint8 session_state = QCDM_CMD_HDR_SUBSYS_STATE_INFO_SESSION_STATE_CLOSED; guint8 almp_state = QCDM_CMD_HDR_SUBSYS_STATE_INFO_ALMP_STATE_INACTIVE; @@ -1801,19 +1817,24 @@ reg_cmstate_cb (MMQcdmSerialPort *port, MMAtSerialPort *at_port = NULL; QCDMResult *result = NULL; guint32 opmode = 0, sysmode = 0; + GError *qcdm_error = NULL; /* Parse the response */ if (!error) - result = qcdm_cmd_cm_subsys_state_info_result ((const char *) response->data, response->len, &info->error); + result = qcdm_cmd_cm_subsys_state_info_result ((const char *) response->data, response->len, &qcdm_error); if (!result) { /* If there was some error, fall back to use +CAD like we did before QCDM */ if (info->modem) at_port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (info->modem), &info->error); + else + info->error = g_error_copy (qcdm_error); + if (at_port) mm_at_serial_port_queue_command (at_port, "+CAD?", 3, get_analog_digital_done, info); else mm_callback_info_schedule (info); + g_clear_error (&qcdm_error); return; } @@ -1856,8 +1877,8 @@ get_registration_state (MMModemCdma *modem, port = mm_generic_cdma_get_best_at_port (MM_GENERIC_CDMA (modem), &info->error); if (!port && !priv->qcdm) { - g_message ("Returning saved registration states: 1x: %d EVDO: %d", - priv->cdma_1x_reg_state, priv->evdo_reg_state); + mm_dbg ("Returning saved registration states: 1x: %d EVDO: %d", + priv->cdma_1x_reg_state, priv->evdo_reg_state); mm_generic_cdma_query_reg_state_set_callback_1x_state (info, priv->cdma_1x_reg_state); mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, priv->evdo_reg_state); mm_callback_info_schedule (info); @@ -2268,6 +2289,9 @@ get_property (GObject *object, guint prop_id, case MM_MODEM_PROP_TYPE: g_value_set_uint (value, MM_MODEM_TYPE_CDMA); break; + case MM_MODEM_CDMA_PROP_MEID: + g_value_set_string (value, priv->meid); + break; case PROP_EVDO_REV0: g_value_set_boolean (value, priv->evdo_rev0); break; @@ -2320,6 +2344,10 @@ mm_generic_cdma_class_init (MMGenericCdmaClass *klass) MM_MODEM_PROP_TYPE, MM_MODEM_TYPE); + g_object_class_override_property (object_class, + MM_MODEM_CDMA_PROP_MEID, + MM_MODEM_CDMA_MEID); + g_object_class_install_property (object_class, PROP_EVDO_REV0, g_param_spec_boolean (MM_GENERIC_CDMA_EVDO_REV0, "EVDO rev0", diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index 7f28dd5c..98713b0d 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -33,7 +33,7 @@ #include "mm-qcdm-serial-port.h" #include "mm-serial-parsers.h" #include "mm-modem-helpers.h" -#include "mm-options.h" +#include "mm-log.h" #include "mm-properties-changed-signal.h" #include "mm-utils.h" #include "mm-modem-location.h" @@ -471,10 +471,8 @@ get_iccid_done (MMModem *modem, g_free (priv->simid); priv->simid = g_strdup (g_checksum_get_string (sum)); - if (mm_options_debug ()) { - g_debug ("SIM ID source '%s'", response); - g_debug ("SIM ID '%s'", priv->simid); - } + mm_dbg ("SIM ID source '%s'", response); + mm_dbg ("SIM ID '%s'", priv->simid); g_object_notify (G_OBJECT (modem), MM_MODEM_GSM_CARD_SIM_IDENTIFIER); @@ -990,6 +988,57 @@ periodic_poll_cb (gpointer user_data) return TRUE; /* continue running */ } +#define CREG_NUM_TAG "creg-num" +#define CGREG_NUM_TAG "cgreg-num" + +static void +initial_unsolicited_reg_check_done (MMCallbackInfo *info) +{ + MMGenericGsmPrivate *priv; + guint creg_num, cgreg_num; + + if (!info->modem || info->error) + goto done; + + priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); + if (!priv->secondary) + goto done; + + /* Enable unsolicited registration responses on secondary ports too, + * to ensure that we get the response even if the modem is connected + * on the primary port. We enable responses on both ports because we + * cannot trust modems to reliably send the responses on the port we + * enable them on. + */ + + creg_num = GPOINTER_TO_UINT (mm_callback_info_get_data (info, CREG_NUM_TAG)); + switch (creg_num) { + case 1: + mm_at_serial_port_queue_command (priv->secondary, "+CREG=1", 3, NULL, NULL); + break; + case 2: + mm_at_serial_port_queue_command (priv->secondary, "+CREG=2", 3, NULL, NULL); + break; + default: + break; + } + + cgreg_num = GPOINTER_TO_UINT (mm_callback_info_get_data (info, CGREG_NUM_TAG)); + switch (cgreg_num) { + case 1: + mm_at_serial_port_queue_command (priv->secondary, "+CGREG=1", 3, NULL, NULL); + break; + case 2: + mm_at_serial_port_queue_command (priv->secondary, "+CGREG=2", 3, NULL, NULL); + break; + default: + break; + } + +done: + mm_callback_info_schedule (info); +} + static void cgreg1_done (MMAtSerialPort *port, GString *response, @@ -1007,11 +1056,14 @@ cgreg1_done (MMAtSerialPort *port, /* The modem doesn't like unsolicited CGREG, so we'll need to poll */ priv->cgreg_poll = TRUE; - } + } else + mm_callback_info_set_data (info, CGREG_NUM_TAG, GUINT_TO_POINTER (1), NULL); + /* Success; get initial state */ mm_at_serial_port_queue_command (port, "+CGREG?", 10, reg_poll_response, info->modem); } - mm_callback_info_schedule (info); + + initial_unsolicited_reg_check_done (info); } static void @@ -1032,11 +1084,13 @@ cgreg2_done (MMAtSerialPort *port, } else { add_loc_capability (MM_GENERIC_GSM (info->modem), MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI); + mm_callback_info_set_data (info, CGREG_NUM_TAG, GUINT_TO_POINTER (2), NULL); + /* Success; get initial state */ mm_at_serial_port_queue_command (port, "+CGREG?", 10, reg_poll_response, info->modem); /* All done */ - mm_callback_info_schedule (info); + initial_unsolicited_reg_check_done (info); } } else { /* Modem got removed */ @@ -1061,7 +1115,9 @@ creg1_done (MMAtSerialPort *port, /* The modem doesn't like unsolicited CREG, so we'll need to poll */ priv->creg_poll = TRUE; - } + } else + mm_callback_info_set_data (info, CREG_NUM_TAG, GUINT_TO_POINTER (1), NULL); + /* Success; get initial state */ mm_at_serial_port_queue_command (port, "+CREG?", 10, reg_poll_response, info->modem); @@ -1090,6 +1146,8 @@ creg2_done (MMAtSerialPort *port, } else { add_loc_capability (MM_GENERIC_GSM (info->modem), MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI); + mm_callback_info_set_data (info, CREG_NUM_TAG, GUINT_TO_POINTER (2), NULL); + /* Success; get initial state */ mm_at_serial_port_queue_command (port, "+CREG?", 10, reg_poll_response, info->modem); @@ -1240,8 +1298,15 @@ cmer_cb (MMAtSerialPort *port, GError *error, gpointer user_data) { - if (!error) - MM_GENERIC_GSM_GET_PRIVATE (user_data)->cmer_enabled = TRUE; + if (!error) { + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (user_data); + + priv->cmer_enabled = TRUE; + + /* Enable CMER on the secondary port if we can too */ + if (priv->secondary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary))) + mm_at_serial_port_queue_command (priv->secondary, "+CMER=3,0,0,1", 3, NULL, NULL); + } } static void @@ -1306,12 +1371,9 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self, */ if (priv->secondary) { if (!mm_serial_port_open (MM_SERIAL_PORT (priv->secondary), &error)) { - if (mm_options_debug ()) { - g_warning ("%s: error opening secondary port: (%d) %s", - __func__, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - } + mm_dbg ("error opening secondary port: (%d) %s", + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); } } @@ -1524,11 +1586,16 @@ disable_flash_done (MMSerialPort *port, priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); /* Disable unsolicited messages */ - mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "AT+CREG=0", 3, NULL, NULL); - mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "AT+CGREG=0", 3, NULL, NULL); + mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "+CREG=0", 3, NULL, NULL); + mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "+CGREG=0", 3, NULL, NULL); if (priv->cmer_enabled) { mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "+CMER=0", 3, NULL, NULL); + + /* And on the secondary port */ + if (priv->secondary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary))) + mm_at_serial_port_queue_command (priv->secondary, "+CMER=0", 3, NULL, NULL); + priv->cmer_enabled = FALSE; } @@ -1541,6 +1608,15 @@ disable_flash_done (MMSerialPort *port, } static void +secondary_unsolicited_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + mm_serial_port_close_force (MM_SERIAL_PORT (port)); +} + +static void disable (MMModem *modem, MMModemFn callback, gpointer user_data) @@ -1575,9 +1651,12 @@ disable (MMModem *modem, update_lac_ci (self, 0, 0, 1); _internal_update_access_technology (self, MM_MODEM_GSM_ACCESS_TECH_UNKNOWN); - /* Close the secondary port if its open */ - if (priv->secondary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary))) - mm_serial_port_close_force (MM_SERIAL_PORT (priv->secondary)); + /* Clean up the secondary port if it's open */ + if (priv->secondary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary))) { + mm_at_serial_port_queue_command (priv->secondary, "+CREG=0", 3, NULL, NULL); + mm_at_serial_port_queue_command (priv->secondary, "+CGREG=0", 3, NULL, NULL); + mm_at_serial_port_queue_command (priv->secondary, "+CMER=0", 3, secondary_unsolicited_done, NULL); + } info = mm_callback_info_new (modem, callback, user_data); @@ -2237,7 +2316,7 @@ roam_disconnect_done (MMModem *modem, GError *error, gpointer user_data) { - g_message ("Disconnected because roaming is not allowed"); + mm_info ("Disconnected because roaming is not allowed"); } static void @@ -2268,9 +2347,9 @@ mm_generic_gsm_set_reg_status (MMGenericGsm *self, if (priv->reg_status[rs_type - 1] == status) return; - g_debug ("%s registration state changed: %d", - (rs_type == MM_GENERIC_GSM_REG_TYPE_CS) ? "CS" : "PS", - status); + mm_dbg ("%s registration state changed: %d", + (rs_type == MM_GENERIC_GSM_REG_TYPE_CS) ? "CS" : "PS", + status); priv->reg_status[rs_type - 1] = status; port = mm_generic_gsm_get_best_at_port (self, NULL); @@ -2389,11 +2468,8 @@ reg_state_changed (MMAtSerialPort *port, GError *error = NULL; if (!mm_gsm_parse_creg_response (match_info, &state, &lac, &cell_id, &act, &cgreg, &error)) { - if (mm_options_debug ()) { - g_warning ("%s: error parsing unsolicited registration: %s", - __func__, - error && error->message ? error->message : "(unknown)"); - } + mm_warn ("error parsing unsolicited registration: %s", + error && error->message ? error->message : "(unknown)"); return; } @@ -3830,10 +3906,10 @@ ussd_update_state (MMGenericGsm *self, MMModemGsmUssdState new_state) } static void -ussd_initiate_done (MMAtSerialPort *port, - GString *response, - GError *error, - gpointer user_data) +ussd_send_done (MMAtSerialPort *port, + GString *response, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; MMGenericGsmPrivate *priv; @@ -3860,10 +3936,7 @@ ussd_initiate_done (MMAtSerialPort *port, case 0: /* no further action required */ ussd_state = MM_MODEM_GSM_USSD_STATE_IDLE; break; - case 1: /* Not an error but not yet implemented */ - info->error = g_error_new (MM_MODEM_ERROR, - MM_MODEM_ERROR_GENERAL, - "Further action required."); + case 1: /* further action required */ ussd_state = MM_MODEM_GSM_USSD_STATE_USER_RESPONSE; break; case 2: @@ -3894,10 +3967,8 @@ ussd_initiate_done (MMAtSerialPort *port, if (reply) { /* look for the reply data coding scheme */ - if (mm_options_debug ()) { - if ((start = strrchr (end, ',')) != NULL) - g_debug ("USSD data coding scheme %d", atoi (start + 1)); - } + if ((start = strrchr (end, ',')) != NULL) + mm_dbg ("USSD data coding scheme %d", atoi (start + 1)); converted = mm_modem_charset_hex_to_utf8 (reply, priv->cur_charset); mm_callback_info_set_result (info, converted, g_free); @@ -3919,10 +3990,10 @@ done: } static void -ussd_initiate (MMModemGsmUssd *modem, - const char *command, - MMModemStringFn callback, - gpointer user_data) +ussd_send (MMModemGsmUssd *modem, + const char *command, + MMModemStringFn callback, + gpointer user_data) { MMCallbackInfo *info; char *atc_command; @@ -3947,13 +4018,57 @@ ussd_initiate (MMModemGsmUssd *modem, atc_command = g_strdup_printf ("+CUSD=1,\"%s\",15", hex); g_free (hex); - mm_at_serial_port_queue_command (port, atc_command, 10, ussd_initiate_done, info); + mm_at_serial_port_queue_command (port, atc_command, 10, ussd_send_done, info); g_free (atc_command); ussd_update_state (MM_GENERIC_GSM (modem), MM_MODEM_GSM_USSD_STATE_ACTIVE); } static void +ussd_initiate (MMModemGsmUssd *modem, + const char *command, + MMModemStringFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem); + info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data); + + if (priv->ussd_state != MM_MODEM_GSM_USSD_STATE_IDLE) { + info->error = g_error_new (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "USSD session already active."); + mm_callback_info_schedule (info); + return; + } + + ussd_send (modem, command, callback, user_data); + return; +} + +static void +ussd_respond (MMModemGsmUssd *modem, + const char *command, + MMModemStringFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem); + info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data); + + if (priv->ussd_state != MM_MODEM_GSM_USSD_STATE_USER_RESPONSE) { + info->error = g_error_new (MM_MODEM_ERROR, + MM_MODEM_ERROR_GENERAL, + "No active USSD session, cannot respond."); + mm_callback_info_schedule (info); + return; + } + + ussd_send (modem, command, callback, user_data); + return; +} + +static void ussd_cancel_done (MMAtSerialPort *port, GString *response, GError *error, @@ -4123,6 +4238,7 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data) gboolean done = FALSE; MMModemGsmAllowedMode allowed_mode; gboolean home_only = FALSE; + char *data_device; info->error = mm_modem_check_removed (modem, error); if (info->error) @@ -4130,16 +4246,9 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data) priv = MM_GENERIC_GSM_GET_PRIVATE (modem); - if (mm_options_debug ()) { - GTimeVal tv; - char *data_device; - - g_object_get (G_OBJECT (modem), MM_MODEM_DATA_DEVICE, &data_device, NULL); - g_get_current_time (&tv); - g_debug ("<%ld.%ld> (%s): simple connect state %d", - tv.tv_sec, tv.tv_usec, data_device, state); - g_free (data_device); - } + g_object_get (G_OBJECT (modem), MM_MODEM_DATA_DEVICE, &data_device, NULL); + mm_dbg ("(%s): simple connect state %d", data_device, state); + g_free (data_device); switch (state) { case SIMPLE_STATE_CHECK_PIN: @@ -4238,29 +4347,21 @@ simple_connect (MMModemSimple *simple, gpointer user_data) { MMCallbackInfo *info; + GHashTableIter iter; + gpointer key, value; + char *data_device; - /* If debugging, list all the simple connect properties */ - if (mm_options_debug ()) { - GHashTableIter iter; - gpointer key, value; - GTimeVal tv; - char *data_device; - - g_object_get (G_OBJECT (simple), MM_MODEM_DATA_DEVICE, &data_device, NULL); - g_get_current_time (&tv); - - g_hash_table_iter_init (&iter, properties); - while (g_hash_table_iter_next (&iter, &key, &value)) { - char *val_str; - - val_str = g_strdup_value_contents ((GValue *) value); - g_debug ("<%ld.%ld> (%s): %s => %s", - tv.tv_sec, tv.tv_usec, - data_device, (const char *) key, val_str); - g_free (val_str); - } - g_free (data_device); + /* List simple connect properties when debugging */ + g_object_get (G_OBJECT (simple), MM_MODEM_DATA_DEVICE, &data_device, NULL); + g_hash_table_iter_init (&iter, properties); + while (g_hash_table_iter_next (&iter, &key, &value)) { + char *val_str; + + val_str = g_strdup_value_contents ((GValue *) value); + mm_dbg ("(%s): %s => %s", data_device, (const char *) key, val_str); + g_free (val_str); } + g_free (data_device); info = mm_callback_info_new (MM_MODEM (simple), callback, user_data); mm_callback_info_set_data (info, "simple-connect-properties", @@ -4633,6 +4734,7 @@ static void modem_gsm_ussd_init (MMModemGsmUssd *class) { class->initiate = ussd_initiate; + class->respond = ussd_respond; class->cancel = ussd_cancel; } diff --git a/src/mm-log.c b/src/mm-log.c new file mode 100644 index 00000000..82d40bc8 --- /dev/null +++ b/src/mm-log.c @@ -0,0 +1,227 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details: + * + * Copyright (C) 2011 Red Hat, Inc. + */ + +#define _GNU_SOURCE +#include <config.h> +#include <stdio.h> +#include <syslog.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> +#include <unistd.h> + +#include "mm-log.h" + +enum { + TS_FLAG_NONE = 0, + TS_FLAG_WALL, + TS_FLAG_REL +}; + +static gboolean ts_flags = TS_FLAG_NONE; +static guint32 log_level = LOGL_INFO | LOGL_WARN | LOGL_ERR; +static GTimeVal rel_start = { 0, 0 }; +static int logfd = -1; + +typedef struct { + guint32 num; + const char *name; +} LogDesc; + +static const LogDesc level_descs[] = { + { LOGL_ERR, "ERR" }, + { LOGL_WARN | LOGL_ERR, "WARN" }, + { LOGL_INFO | LOGL_WARN | LOGL_ERR, "INFO" }, + { LOGL_DEBUG | LOGL_INFO | LOGL_WARN | LOGL_ERR, "DEBUG" }, + { 0, NULL } +}; + +void +_mm_log (const char *loc, + const char *func, + guint32 level, + const char *fmt, + ...) +{ + va_list args; + char *msg; + GTimeVal tv; + char tsbuf[100] = { 0 }; + char msgbuf[512] = { 0 }; + int syslog_priority = LOG_INFO; + const char *prefix = NULL; + + if (!(log_level & level)) + return; + + va_start (args, fmt); + msg = g_strdup_vprintf (fmt, args); + va_end (args); + + if (ts_flags == TS_FLAG_WALL) { + g_get_current_time (&tv); + snprintf (&tsbuf[0], sizeof (tsbuf), " [%09ld.%06ld]", tv.tv_sec, tv.tv_usec); + } else if (ts_flags == TS_FLAG_REL) { + time_t secs; + suseconds_t usecs; + + g_get_current_time (&tv); + secs = tv.tv_sec - rel_start.tv_sec; + usecs = tv.tv_usec - rel_start.tv_usec; + if (usecs < 0) { + secs--; + usecs += 1000000; + } + + snprintf (&tsbuf[0], sizeof (tsbuf), " [%06ld.%06ld]", secs, usecs); + } + + if ((log_level & LOGL_DEBUG) && (level == LOGL_DEBUG)) + prefix = "debug"; + else if ((log_level & LOGL_INFO) && (level == LOGL_INFO)) + prefix = "info"; + else if ((log_level & LOGL_WARN) && (level == LOGL_WARN)) { + prefix = "warn"; + syslog_priority = LOG_WARNING; + } else if ((log_level & LOGL_ERR) && (level == LOGL_ERR)) { + prefix = "err"; + syslog_priority = LOG_ERR; + } else + g_warn_if_reached (); + + if (prefix) { + if (log_level & LOGL_DEBUG) + snprintf (msgbuf, sizeof (msgbuf), "<%s>%s [%s] %s(): %s\n", prefix, tsbuf, loc, func, msg); + else + snprintf (msgbuf, sizeof (msgbuf), "<%s>%s %s\n", prefix, tsbuf, msg); + + if (logfd < 0) + syslog (syslog_priority, "%s", msgbuf); + else { + write (logfd, msgbuf, strlen (msgbuf)); + fsync (logfd); /* Make sure output is dumped to disk immediately */ + } + } + + g_free (msg); +} + +static void +log_handler (const gchar *log_domain, + GLogLevelFlags level, + const gchar *message, + gpointer ignored) +{ + int syslog_priority; + + switch (level) { + case G_LOG_LEVEL_ERROR: + syslog_priority = LOG_CRIT; + break; + case G_LOG_LEVEL_CRITICAL: + syslog_priority = LOG_ERR; + break; + case G_LOG_LEVEL_WARNING: + syslog_priority = LOG_WARNING; + break; + case G_LOG_LEVEL_MESSAGE: + syslog_priority = LOG_NOTICE; + break; + case G_LOG_LEVEL_DEBUG: + syslog_priority = LOG_DEBUG; + break; + case G_LOG_LEVEL_INFO: + default: + syslog_priority = LOG_INFO; + break; + } + + if (logfd < 0) + syslog (syslog_priority, "%s", message); + else + write (logfd, message, strlen (message)); +} + +gboolean +mm_log_setup (const char *level, + const char *log_file, + gboolean show_timestamps, + gboolean rel_timestamps, + GError **error) +{ + /* levels */ + if (level && strlen (level)) { + gboolean found = FALSE; + const LogDesc *diter; + + for (diter = &level_descs[0]; diter->name; diter++) { + if (!strcasecmp (diter->name, level)) { + log_level = diter->num; + found = TRUE; + break; + } + } + + if (!found) { + g_set_error (error, 0, 0, "Unknown log level '%s'", level); + return FALSE; + } + } + + if (show_timestamps) + ts_flags = TS_FLAG_WALL; + else if (rel_timestamps) + ts_flags = TS_FLAG_REL; + + /* Grab start time for relative timestamps */ + g_get_current_time (&rel_start); + + if (log_file == NULL) + openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PID | LOG_PERROR, LOG_DAEMON); + else { + logfd = open (log_file, + O_CREAT | O_APPEND | O_WRONLY, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (logfd < 0) { + g_set_error (error, 0, 0, "Failed to open log file: (%d) %s", + errno, strerror (errno)); + return FALSE; + } + } + + g_log_set_handler (G_LOG_DOMAIN, + G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, + log_handler, + NULL); + + return TRUE; +} + +void +mm_log_usr1 (void) +{ +} + +void +mm_log_shutdown (void) +{ + if (logfd < 0) + closelog (); + else + close (logfd); +} + diff --git a/src/mm-log.h b/src/mm-log.h new file mode 100644 index 00000000..9b0d875f --- /dev/null +++ b/src/mm-log.h @@ -0,0 +1,61 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details: + * + * Copyright (C) 2011 Red Hat, Inc. + */ + +#ifndef MM_LOG_H +#define MM_LOG_H + +#include <glib.h> + +/* Log levels */ +enum { + LOGL_ERR = 0x00000001, + LOGL_WARN = 0x00000002, + LOGL_INFO = 0x00000004, + LOGL_DEBUG = 0x00000008 +}; + +#define mm_err(...) \ + _mm_log (G_STRLOC, G_STRFUNC, LOGL_ERR, ## __VA_ARGS__ ) + +#define mm_warn(...) \ + _mm_log (G_STRLOC, G_STRFUNC, LOGL_WARN, ## __VA_ARGS__ ) + +#define mm_info(...) \ + _mm_log (G_STRLOC, G_STRFUNC, LOGL_INFO, ## __VA_ARGS__ ) + +#define mm_dbg(...) \ + _mm_log (G_STRLOC, G_STRFUNC, LOGL_DEBUG, ## __VA_ARGS__ ) + +#define mm_log(level, ...) \ + _mm_log (G_STRLOC, G_STRFUNC, level, ## __VA_ARGS__ ) + +void _mm_log (const char *loc, + const char *func, + guint32 level, + const char *fmt, + ...) __attribute__((__format__ (__printf__, 4, 5))); + +gboolean mm_log_setup (const char *level, + const char *log_file, + gboolean show_ts, + gboolean rel_ts, + GError **error); + +void mm_log_usr1 (void); + +void mm_log_shutdown (void); + +#endif /* MM_LOG_H */ + diff --git a/src/mm-manager.c b/src/mm-manager.c index 605ec5a1..561d427c 100644 --- a/src/mm-manager.c +++ b/src/mm-manager.c @@ -24,6 +24,7 @@ #include "mm-manager.h" #include "mm-errors.h" #include "mm-plugin.h" +#include "mm-log.h" static gboolean impl_manager_enumerate_devices (MMManager *manager, GPtrArray **devices, @@ -112,9 +113,9 @@ load_plugin (const char *path) plugin = (*plugin_create_func) (); if (plugin) { g_object_weak_ref (G_OBJECT (plugin), (GWeakNotify) g_module_close, module); - g_message ("Loaded plugin %s", mm_plugin_get_name (plugin)); + mm_info ("Loaded plugin %s", mm_plugin_get_name (plugin)); } else - g_warning ("Could not load plugin %s: initialization failed", path); + mm_warn ("Could not load plugin %s: initialization failed", path); out: if (!plugin) @@ -196,7 +197,7 @@ remove_modem (MMManager *manager, MMModem *modem) device = mm_modem_get_device (modem); g_assert (device); - g_debug ("Removed modem %s", device); + mm_dbg ("Removed modem %s", device); g_signal_emit (manager, signals[DEVICE_REMOVED], 0, modem); g_hash_table_remove (priv->modems, device); @@ -234,8 +235,8 @@ check_export_modem (MMManager *self, MMModem *modem) SupportsInfo *info = value; if (!strcmp (info->physdev_path, modem_physdev)) { - g_debug ("(%s/%s): outstanding support task prevents export of %s", - info->subsys, info->name, modem_physdev); + mm_dbg ("(%s/%s): outstanding support task prevents export of %s", + info->subsys, info->name, modem_physdev); goto out; } } @@ -257,7 +258,7 @@ check_export_modem (MMManager *self, MMModem *modem) dbus_g_connection_register_g_object (priv->connection, path, G_OBJECT (modem)); g_object_set_data_full (G_OBJECT (modem), DBUS_PATH_TAG, path, (GDestroyNotify) g_free); - g_debug ("Exported modem %s as %s", modem_physdev, path); + mm_dbg ("Exported modem %s as %s", modem_physdev, path); physdev = g_udev_client_query_by_sysfs_path (priv->udev, modem_physdev); if (physdev) @@ -268,10 +269,10 @@ check_export_modem (MMManager *self, MMModem *modem) MM_MODEM_HW_VID, &vid, MM_MODEM_HW_PID, &pid, NULL); - g_debug ("(%s): VID 0x%04X PID 0x%04X (%s)", + mm_dbg ("(%s): VID 0x%04X PID 0x%04X (%s)", path, (vid & 0xFFFF), (pid & 0xFFFF), subsys ? subsys : "unknown"); - g_debug ("(%s): data port is %s", path, data_device); + mm_dbg ("(%s): data port is %s", path, data_device); g_free (data_device); if (physdev) @@ -309,7 +310,7 @@ add_modem (MMManager *manager, MMModem *modem, MMPlugin *plugin) g_hash_table_insert (priv->modems, g_strdup (device), modem); g_object_set_data (G_OBJECT (modem), MANAGER_PLUGIN_TAG, plugin); - g_debug ("Added modem %s", device); + mm_dbg ("Added modem %s", device); g_signal_connect (modem, "notify::" MM_MODEM_VALID, G_CALLBACK (modem_valid), manager); check_export_modem (manager, modem); } @@ -446,7 +447,7 @@ supports_defer_timeout (gpointer user_data) existing = find_modem_for_device (info->manager, info->physdev_path); - g_debug ("(%s): re-checking support...", info->name); + mm_dbg ("(%s): re-checking support...", info->name); try_supports_port (info->manager, MM_PLUGIN (info->cur_plugin->data), existing, @@ -478,9 +479,9 @@ try_supports_port (MMManager *manager, supports_callback (plugin, info->subsys, info->name, 0, info); break; case MM_PLUGIN_SUPPORTS_PORT_DEFER: - g_debug ("(%s): (%s) deferring support check", - mm_plugin_get_name (plugin), - info->name); + mm_dbg ("(%s): (%s) deferring support check", + mm_plugin_get_name (plugin), + info->name); if (info->defer_id) g_source_remove (info->defer_id); @@ -549,22 +550,21 @@ do_grab_port (gpointer user_data) type_name = "CDMA"; device = mm_modem_get_device (modem); - g_message ("(%s): %s modem %s claimed port %s", - mm_plugin_get_name (info->best_plugin), - type_name, - device, - info->name); + mm_info ("(%s): %s modem %s claimed port %s", + mm_plugin_get_name (info->best_plugin), + type_name, + device, + info->name); g_free (device); add_modem (info->manager, modem, info->best_plugin); } else { - g_warning ("%s: plugin '%s' claimed to support %s/%s but couldn't: (%d) %s", - __func__, - mm_plugin_get_name (info->best_plugin), - info->subsys, - info->name, - error ? error->code : -1, - (error && error->message) ? error->message : "(unknown)"); + mm_warn ("plugin '%s' claimed to support %s/%s but couldn't: (%d) %s", + mm_plugin_get_name (info->best_plugin), + info->subsys, + info->name, + error ? error->code : -1, + (error && error->message) ? error->message : "(unknown)"); modem = existing; } } @@ -613,8 +613,8 @@ supports_callback (MMPlugin *plugin, * support this port, but this plugin is clearly the right plugin * since it claimed this port's physical modem, just drop the port. */ - g_debug ("(%s/%s): ignoring port unsupported by physical modem's plugin", - info->subsys, info->name); + mm_dbg ("(%s/%s): ignoring port unsupported by physical modem's plugin", + info->subsys, info->name); supports_cleanup (info->manager, info->subsys, info->name, existing); return; } @@ -631,14 +631,14 @@ supports_callback (MMPlugin *plugin, */ next_plugin = existing_plugin; } else { - g_debug ("(%s/%s): plugin %p (%s) existing %p (%s) info->best %p (%s)", - info->subsys, info->name, - plugin, - plugin ? mm_plugin_get_name (plugin) : "none", - existing_plugin, - existing_plugin ? mm_plugin_get_name (existing_plugin) : "none", - info->best_plugin, - info->best_plugin ? mm_plugin_get_name (info->best_plugin) : "none"); + mm_dbg ("(%s/%s): plugin %p (%s) existing %p (%s) info->best %p (%s)", + info->subsys, info->name, + plugin, + plugin ? mm_plugin_get_name (plugin) : "none", + existing_plugin, + existing_plugin ? mm_plugin_get_name (existing_plugin) : "none", + info->best_plugin, + info->best_plugin ? mm_plugin_get_name (info->best_plugin) : "none"); g_assert_not_reached (); } } else { @@ -783,14 +783,14 @@ device_added (MMManager *manager, GUdevDevice *device) && strcmp (name, "lo") && strcmp (name, "tty") && !strstr (name, "virbr")) - g_debug ("(%s/%s): could not get port's parent device", subsys, name); + mm_dbg ("(%s/%s): could not get port's parent device", subsys, name); goto out; } /* Is the device blacklisted? */ if (g_udev_device_get_property_as_boolean (physdev, "ID_MM_DEVICE_IGNORE")) { - g_debug ("(%s/%s): port's parent device is blacklisted", subsys, name); + mm_dbg ("(%s/%s): port's parent device is blacklisted", subsys, name); goto out; } @@ -799,13 +799,13 @@ device_added (MMManager *manager, GUdevDevice *device) if ( physdev_subsys && !strcmp (physdev_subsys, "platform") && !g_udev_device_get_property_as_boolean (physdev, "ID_MM_PLATFORM_DRIVER_PROBE")) { - g_debug ("(%s/%s): port's parent platform driver is not whitelisted", subsys, name); + mm_dbg ("(%s/%s): port's parent platform driver is not whitelisted", subsys, name); goto out; } physdev_path = g_udev_device_get_sysfs_path (physdev); if (!physdev_path) { - g_debug ("(%s/%s): could not get port's parent device sysfs path", subsys, name); + mm_dbg ("(%s/%s): could not get port's parent device sysfs path", subsys, name); goto out; } @@ -836,7 +836,7 @@ device_removed (MMManager *manager, GUdevDevice *device) MMManagerPrivate *priv = MM_MANAGER_GET_PRIVATE (manager); MMModem *modem; const char *subsys, *name; - char *key; + char *key, *modem_device; SupportsInfo *info; g_return_if_fail (device != NULL); @@ -851,6 +851,9 @@ device_removed (MMManager *manager, GUdevDevice *device) /* find_modem_for_port handles tty and net removal */ modem = find_modem_for_port (manager, subsys, name); if (modem) { + modem_device = mm_modem_get_device (modem); + mm_info ("(%s/%s): released by modem %s", subsys, name, modem_device); + g_free (modem_device); mm_modem_release_port (modem, subsys, name); return; } @@ -865,10 +868,9 @@ device_removed (MMManager *manager, GUdevDevice *device) */ const char *sysfs_path = g_udev_device_get_sysfs_path (device); - // g_debug ("Looking for a modem for removed device %s", sysfs_path); modem = find_modem_for_device (manager, sysfs_path); if (modem) { - g_debug ("Removing modem claimed by removed device %s", sysfs_path); + mm_dbg ("Removing modem claimed by removed device %s", sysfs_path); remove_modem (manager, modem); return; } diff --git a/src/mm-modem-base.c b/src/mm-modem-base.c index 50088fb5..ee5e1c86 100644 --- a/src/mm-modem-base.c +++ b/src/mm-modem-base.c @@ -25,7 +25,7 @@ #include "mm-at-serial-port.h" #include "mm-qcdm-serial-port.h" #include "mm-errors.h" -#include "mm-options.h" +#include "mm-log.h" #include "mm-properties-changed-signal.h" #include "mm-callback-info.h" #include "mm-modem-helpers.h" @@ -148,15 +148,13 @@ mm_modem_base_add_port (MMModemBase *self, if (!port) return NULL; - if (mm_options_debug ()) { - device = mm_modem_get_device (MM_MODEM (self)); + device = mm_modem_get_device (MM_MODEM (self)); + mm_dbg ("(%s) type %s claimed by %s", + name, + mm_port_type_to_name (ptype), + device); + g_free (device); - g_message ("(%s) type %s claimed by %s", - name, - mm_port_type_to_name (ptype), - device); - g_free (device); - } key = get_hash_key (subsys, name); g_hash_table_insert (priv->ports, key, port); return port; @@ -165,10 +163,32 @@ mm_modem_base_add_port (MMModemBase *self, gboolean mm_modem_base_remove_port (MMModemBase *self, MMPort *port) { + MMModemBasePrivate *priv; + char *device, *key, *name; + const char *type_name, *subsys; + gboolean removed; + g_return_val_if_fail (MM_IS_MODEM_BASE (self), FALSE); g_return_val_if_fail (port != NULL, FALSE); - return g_hash_table_remove (MM_MODEM_BASE_GET_PRIVATE (self)->ports, port); + priv = MM_MODEM_BASE_GET_PRIVATE (self); + + name = g_strdup (mm_port_get_device (port)); + subsys = mm_port_subsys_to_name (mm_port_get_subsys (port)); + type_name = mm_port_type_to_name (mm_port_get_port_type (port)); + + key = get_hash_key (subsys, name); + removed = g_hash_table_remove (priv->ports, key); + if (removed) { + /* Port may have already been destroyed by removal from the hash */ + device = mm_modem_get_device (MM_MODEM (self)); + mm_dbg ("(%s) type %s removed from %s", name, type_name, device); + g_free (device); + } + g_free (key); + g_free (name); + + return removed; } void @@ -233,9 +253,9 @@ mm_modem_base_set_equipment_identifier (MMModemBase *self, const char *ident) dbus_path = (const char *) g_object_get_data (G_OBJECT (self), DBUS_PATH_TAG); if (dbus_path) { if (priv->equipment_ident) - g_message ("Modem %s: Equipment identifier set (%s)", dbus_path, priv->equipment_ident); + mm_info ("Modem %s: Equipment identifier set (%s)", dbus_path, priv->equipment_ident); else - g_message ("Modem %s: Equipment identifier not set", dbus_path); + mm_warn ("Modem %s: Equipment identifier not set", dbus_path); } g_object_notify (G_OBJECT (self), MM_MODEM_EQUIPMENT_IDENTIFIER); @@ -274,9 +294,9 @@ mm_modem_base_set_unlock_required (MMModemBase *self, const char *unlock_require dbus_path = (const char *) g_object_get_data (G_OBJECT (self), DBUS_PATH_TAG); if (dbus_path) { if (priv->unlock_required) - g_message ("Modem %s: unlock required (%s)", dbus_path, priv->unlock_required); + mm_info ("Modem %s: unlock required (%s)", dbus_path, priv->unlock_required); else - g_message ("Modem %s: unlock no longer required", dbus_path); + mm_info ("Modem %s: unlock no longer required", dbus_path); } g_object_notify (G_OBJECT (self), MM_MODEM_UNLOCK_REQUIRED); @@ -311,11 +331,11 @@ mm_modem_base_set_unlock_retries (MMModemBase *self, guint unlock_retries) dbus_path = (const char *) g_object_get_data (G_OBJECT (self), DBUS_PATH_TAG); if (dbus_path) { if (priv->unlock_required) { - g_message ("Modem %s: # unlock retries for %s is %d", - dbus_path, priv->unlock_required, priv->unlock_retries); + mm_info ("Modem %s: # unlock retries for %s is %d", + dbus_path, priv->unlock_required, priv->unlock_retries); } else { - g_message ("Modem %s: # unlock retries is %d", - dbus_path, priv->unlock_retries); + mm_info ("Modem %s: # unlock retries is %d", + dbus_path, priv->unlock_retries); } } @@ -446,8 +466,7 @@ card_info_cache_invoke (MMCallbackInfo *info) priv->gsn, priv->revision, priv->model, - priv->manf, - mm_options_debug ()); + priv->manf); g_object_notify (G_OBJECT (self), MM_MODEM_DEVICE_IDENTIFIER); callback (info->modem, priv->manf, priv->model, priv->revision, info->error, info->user_data); @@ -626,6 +645,10 @@ mm_modem_base_init (MMModemBase *self) MM_MODEM_UNLOCK_RETRIES, NULL, MM_MODEM_DBUS_INTERFACE); + mm_properties_changed_signal_register_property (G_OBJECT (self), + MM_MODEM_IP_METHOD, + NULL, + MM_MODEM_DBUS_INTERFACE); } static void diff --git a/src/mm-modem-cdma.c b/src/mm-modem-cdma.c index 3f4ffe54..722918e0 100644 --- a/src/mm-modem-cdma.c +++ b/src/mm-modem-cdma.c @@ -357,6 +357,15 @@ mm_modem_cdma_init (gpointer g_iface) if (initialized) return; + /* Properties */ + g_object_interface_install_property + (g_iface, + g_param_spec_string (MM_MODEM_CDMA_MEID, + "MEID", + "MEID", + NULL, + G_PARAM_READABLE)); + /* Signals */ signals[SIGNAL_QUALITY] = g_signal_new ("signal-quality", diff --git a/src/mm-modem-cdma.h b/src/mm-modem-cdma.h index 89751518..4d30386a 100644 --- a/src/mm-modem-cdma.h +++ b/src/mm-modem-cdma.h @@ -35,6 +35,14 @@ typedef enum { #define MM_MODEM_CDMA_REGISTRATION_STATE_CHANGED "registration-state-changed" +#define MM_MODEM_CDMA_MEID "meid" + +typedef enum { + MM_MODEM_CDMA_PROP_FIRST = 0x1200, + + MM_MODEM_CDMA_PROP_MEID = MM_MODEM_CDMA_PROP_FIRST, +} MMModemCdmaProp; + typedef struct _MMModemCdma MMModemCdma; typedef void (*MMModemCdmaServingSystemFn) (MMModemCdma *modem, diff --git a/src/mm-modem-gsm-network.c b/src/mm-modem-gsm-network.c index 4cd69218..75ca7de9 100644 --- a/src/mm-modem-gsm-network.c +++ b/src/mm-modem-gsm-network.c @@ -108,6 +108,8 @@ mm_modem_gsm_network_act_to_old_mode (MMModemGsmAccessTech act) return MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_HSUPA; else if (act & MM_MODEM_GSM_ACCESS_TECH_HSPA) return MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_HSPA; + else if (act & MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS) + return MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_HSPA; return MM_MODEM_GSM_NETWORK_DEPRECATED_MODE_ANY; } diff --git a/src/mm-modem-gsm-ussd.c b/src/mm-modem-gsm-ussd.c index def22134..f90a8458 100644 --- a/src/mm-modem-gsm-ussd.c +++ b/src/mm-modem-gsm-ussd.c @@ -106,6 +106,23 @@ mm_modem_gsm_ussd_initiate (MMModemGsmUssd *self, } void +mm_modem_gsm_ussd_respond (MMModemGsmUssd *self, + const char *command, + MMModemStringFn callback, + gpointer user_data) +{ + g_return_if_fail (MM_IS_MODEM_GSM_USSD (self)); + g_return_if_fail (command != NULL); + g_return_if_fail (callback != NULL); + + if (MM_MODEM_GSM_USSD_GET_INTERFACE (self)->respond) + MM_MODEM_GSM_USSD_GET_INTERFACE (self)->respond(self, command, callback, user_data); + else + str_call_not_supported (self, callback, user_data); + +} + +void mm_modem_gsm_ussd_cancel (MMModemGsmUssd *self, MMModemFn callback, gpointer user_data) @@ -149,16 +166,6 @@ ussd_auth_info_new (const char* command) /*****************************************************************************/ static void -impl_modem_gsm_ussd_respond (MMModemGsmUssd *modem, - const char *responste, - DBusGMethodInvocation *context) -{ - async_call_not_supported (modem, async_call_done, context); -} - -/*****************************************************************************/ - -static void ussd_initiate_auth_cb (MMAuthRequest *req, GObject *owner, DBusGMethodInvocation *context, @@ -209,6 +216,56 @@ impl_modem_gsm_ussd_initiate (MMModemGsmUssd *modem, } static void +ussd_respond_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModemGsmUssd *self = MM_MODEM_GSM_USSD (owner); + UssdAuthInfo *info = user_data; + GError *error = NULL; + + /* Return any authorization error, otherwise respond to the USSD */ + if (!mm_modem_auth_finish (MM_MODEM (self), req, &error)) + goto done; + + if (!info->command) { + error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Missing USSD command"); + } + +done: + if (error) { + str_call_done (MM_MODEM (self), NULL, error, context); + g_error_free (error); + } else + mm_modem_gsm_ussd_respond (self, info->command, str_call_done, context); +} + +static void +impl_modem_gsm_ussd_respond (MMModemGsmUssd *modem, + const char *command, + DBusGMethodInvocation *context) +{ + GError *error = NULL; + UssdAuthInfo *info; + + info = ussd_auth_info_new (command); + + /* Make sure the caller is authorized to respond to the USSD */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_USSD, + context, + ussd_respond_auth_cb, + info, + ussd_auth_info_destroy, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +static void ussd_cancel_auth_cb (MMAuthRequest *req, GObject *owner, DBusGMethodInvocation *context, diff --git a/src/mm-modem-gsm-ussd.h b/src/mm-modem-gsm-ussd.h index d0da59be..c8f652b9 100644 --- a/src/mm-modem-gsm-ussd.h +++ b/src/mm-modem-gsm-ussd.h @@ -46,6 +46,11 @@ struct _MMModemGsmUssd { MMModemStringFn callback, gpointer user_data); + void (*respond) (MMModemGsmUssd *modem, + const char *command, + MMModemStringFn callback, + gpointer user_data); + void (*cancel) (MMModemGsmUssd *modem, MMModemFn callback, gpointer user_data); @@ -58,6 +63,11 @@ void mm_modem_gsm_ussd_initiate (MMModemGsmUssd *self, MMModemStringFn callback, gpointer user_data); +void mm_modem_gsm_ussd_respond (MMModemGsmUssd *self, + const char *command, + MMModemStringFn callback, + gpointer user_data); + void mm_modem_gsm_ussd_cancel (MMModemGsmUssd *self, MMModemFn callback, gpointer user_data); diff --git a/src/mm-modem-gsm.h b/src/mm-modem-gsm.h index 6d9135a4..a427d354 100644 --- a/src/mm-modem-gsm.h +++ b/src/mm-modem-gsm.h @@ -54,8 +54,9 @@ typedef enum { MM_MODEM_GSM_ACCESS_TECH_HSDPA = 6, /* UTRAN w/HSDPA */ MM_MODEM_GSM_ACCESS_TECH_HSUPA = 7, /* UTRAN w/HSUPA */ MM_MODEM_GSM_ACCESS_TECH_HSPA = 8, /* UTRAN w/HSDPA and HSUPA */ + MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS = 9, /* UTRAN w/HSPA+ */ - MM_MODEM_GSM_ACCESS_TECH_LAST = MM_MODEM_GSM_ACCESS_TECH_HSPA + MM_MODEM_GSM_ACCESS_TECH_LAST = MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS } MMModemGsmAccessTech; typedef enum { diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index 25998b1f..f13b4f27 100644 --- a/src/mm-modem-helpers.c +++ b/src/mm-modem-helpers.c @@ -25,6 +25,7 @@ #include "mm-errors.h" #include "mm-modem-helpers.h" +#include "mm-log.h" const char * mm_strip_tag (const char *str, const char *cmd) @@ -242,10 +243,14 @@ mm_gsm_destroy_scan_data (gpointer data) /* +CREG: <n>,<stat>,<lac>,<ci>,<AcT> (ETSI 27.007 solicited and some CREG=2 unsolicited) */ #define CREG6 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*(\\d{1,2})" +/* +CREG: <n>,<stat>,<lac>,<ci>,<AcT?>,<something> (Samsung Wave S8500) */ +/* '<CR><LF>+CREG: 2,1,000B,2816, B, C2816<CR><LF><CR><LF>OK<CR><LF>' */ +#define CREG7 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*[^,\\s]*" + GPtrArray * mm_gsm_creg_regex_get (gboolean solicited) { - GPtrArray *array = g_ptr_array_sized_new (6); + GPtrArray *array = g_ptr_array_sized_new (7); GRegex *regex; /* #1 */ @@ -296,6 +301,14 @@ mm_gsm_creg_regex_get (gboolean solicited) g_assert (regex); g_ptr_array_add (array, regex); + /* #7 */ + if (solicited) + regex = g_regex_new (CREG7 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + else + regex = g_regex_new ("\\r\\n" CREG7 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + g_assert (regex); + g_ptr_array_add (array, regex); + return array; } @@ -785,7 +798,9 @@ mm_gsm_string_to_access_tech (const char *string) /* Better technologies are listed first since modems sometimes say * stuff like "GPRS/EDGE" and that should be handled as EDGE. */ - if (strcasestr (string, "HSPA")) + if (strcasestr (string, "HSPA+")) + return MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS; + else if (strcasestr (string, "HSPA")) return MM_MODEM_GSM_ACCESS_TECH_HSPA; else if (strcasestr (string, "HSDPA/HSUPA")) return MM_MODEM_GSM_ACCESS_TECH_HSPA; @@ -815,10 +830,9 @@ mm_create_device_identifier (guint vid, const char *gsn, const char *revision, const char *model, - const char *manf, - gboolean debug) + const char *manf) { - GString *devid, *dbg = NULL; + GString *devid, *msg = NULL; GChecksum *sum; char *p, *ret = NULL; char str_vid[10], str_pid[10]; @@ -845,41 +859,35 @@ mm_create_device_identifier (guint vid, return NULL; p = devid->str; - if (debug) - dbg = g_string_sized_new (strlen (devid->str) + 17); + msg = g_string_sized_new (strlen (devid->str) + 17); sum = g_checksum_new (G_CHECKSUM_SHA1); if (vid) { snprintf (str_vid, sizeof (str_vid) - 1, "%08x", vid); g_checksum_update (sum, (const guchar *) &str_vid[0], strlen (str_vid)); - if (dbg) - g_string_append_printf (dbg, "%08x", vid); + g_string_append_printf (msg, "%08x", vid); } if (vid) { snprintf (str_pid, sizeof (str_pid) - 1, "%08x", pid); g_checksum_update (sum, (const guchar *) &str_pid[0], strlen (str_pid)); - if (dbg) - g_string_append_printf (dbg, "%08x", pid); + g_string_append_printf (msg, "%08x", pid); } while (*p) { /* Strip spaces and linebreaks */ if (!isblank (*p) && !isspace (*p) && isascii (*p)) { g_checksum_update (sum, (const guchar *) p, 1); - if (dbg) - g_string_append_c (dbg, *p); + g_string_append_c (msg, *p); } p++; } ret = g_strdup (g_checksum_get_string (sum)); g_checksum_free (sum); - if (dbg) { - g_debug ("Device ID source '%s'", dbg->str); - g_debug ("Device ID '%s'", ret); - g_string_free (dbg, TRUE); - } + mm_dbg ("Device ID source '%s'", msg->str); + mm_dbg ("Device ID '%s'", ret); + g_string_free (msg, TRUE); return ret; } diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h index eda6e5d7..71ccaa5d 100644 --- a/src/mm-modem-helpers.h +++ b/src/mm-modem-helpers.h @@ -66,8 +66,7 @@ char *mm_create_device_identifier (guint vid, const char *gsn, const char *revision, const char *model, - const char *manf, - gboolean debug); + const char *manf); typedef struct CindResponse CindResponse; GHashTable *mm_parse_cind_test_response (const char *reply, GError **error); diff --git a/src/mm-modem.c b/src/mm-modem.c index c65bee54..f8234723 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -18,7 +18,7 @@ #include <string.h> #include <dbus/dbus-glib.h> #include "mm-modem.h" -#include "mm-options.h" +#include "mm-log.h" #include "mm-errors.h" #include "mm-callback-info.h" #include "mm-marshal.h" @@ -28,6 +28,7 @@ static void impl_modem_connect (MMModem *modem, const char *number, DBusGMethodI static void impl_modem_disconnect (MMModem *modem, DBusGMethodInvocation *context); static void impl_modem_get_ip4_config (MMModem *modem, DBusGMethodInvocation *context); static void impl_modem_get_info (MMModem *modem, DBusGMethodInvocation *context); +static void impl_modem_reset (MMModem *modem, DBusGMethodInvocation *context); static void impl_modem_factory_reset (MMModem *modem, const char *code, DBusGMethodInvocation *context); #include "mm-modem-glue.h" @@ -478,6 +479,56 @@ impl_modem_get_info (MMModem *modem, /*****************************************************************************/ static void +reset_auth_cb (MMAuthRequest *req, + GObject *owner, + DBusGMethodInvocation *context, + gpointer user_data) +{ + MMModem *self = MM_MODEM (owner); + GError *error = NULL; + + /* Return any authorization error, otherwise try to reset the modem */ + if (!mm_modem_auth_finish (self, req, &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } else + mm_modem_reset (self, async_call_done, context); +} + +static void +impl_modem_reset (MMModem *modem, DBusGMethodInvocation *context) +{ + GError *error = NULL; + + /* Make sure the caller is authorized to reset the device */ + if (!mm_modem_auth_request (MM_MODEM (modem), + MM_AUTHORIZATION_DEVICE_CONTROL, + context, + reset_auth_cb, + NULL, NULL, + &error)) { + dbus_g_method_return_error (context, error); + g_error_free (error); + } +} + +void +mm_modem_reset (MMModem *self, + MMModemFn callback, + gpointer user_data) +{ + g_return_if_fail (MM_IS_MODEM (self)); + g_return_if_fail (callback != NULL); + + if (MM_MODEM_GET_INTERFACE (self)->reset) + MM_MODEM_GET_INTERFACE (self)->reset (self, callback, user_data); + else + async_op_not_supported (self, callback, user_data); +} + +/*****************************************************************************/ + +static void factory_reset_auth_cb (MMAuthRequest *req, GObject *owner, DBusGMethodInvocation *context, @@ -704,22 +755,10 @@ mm_modem_set_state (MMModem *self, dbus_path = (const char *) g_object_get_data (G_OBJECT (self), DBUS_PATH_TAG); if (dbus_path) { - if (mm_options_debug ()) { - GTimeVal tv; - - g_get_current_time (&tv); - g_debug ("<%ld.%ld> Modem %s: state changed (%s -> %s)", - tv.tv_sec, - tv.tv_usec, - dbus_path, - state_to_string (old_state), - state_to_string (new_state)); - } else { - g_message ("Modem %s: state changed (%s -> %s)", - dbus_path, - state_to_string (old_state), - state_to_string (new_state)); - } + mm_info ("Modem %s: state changed (%s -> %s)", + dbus_path, + state_to_string (old_state), + state_to_string (new_state)); } } } diff --git a/src/mm-modem.h b/src/mm-modem.h index 1faf3838..8a755d88 100644 --- a/src/mm-modem.h +++ b/src/mm-modem.h @@ -194,6 +194,10 @@ struct _MMModem { MMAuthRequest *req, GError **error); + void (*reset) (MMModem *self, + MMModemFn callback, + gpointer user_data); + void (*factory_reset) (MMModem *self, const char *code, MMModemFn callback, @@ -257,6 +261,10 @@ void mm_modem_set_charset (MMModem *self, MMModemFn callback, gpointer user_data); +void mm_modem_reset (MMModem *self, + MMModemFn callback, + gpointer user_data); + void mm_modem_factory_reset (MMModem *self, const char *code, MMModemFn callback, diff --git a/src/mm-options.c b/src/mm-options.c deleted file mode 100644 index 7bbeefd6..00000000 --- a/src/mm-options.c +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details: - * - * Copyright (C) 2008 Novell, Inc. - */ - -#include <stdlib.h> -#include <glib.h> -#include "mm-options.h" - -static gboolean debug = FALSE; - -void -mm_options_parse (int argc, char *argv[]) -{ - GOptionContext *opt_ctx; - GError *error = NULL; - GOptionEntry entries[] = { - { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Output to console rather than syslog", NULL }, - { NULL } - }; - - opt_ctx = g_option_context_new (NULL); - g_option_context_set_summary (opt_ctx, "DBus system service to communicate with modems."); - g_option_context_add_main_entries (opt_ctx, entries, NULL); - - if (!g_option_context_parse (opt_ctx, &argc, &argv, &error)) { - g_warning ("%s\n", error->message); - g_error_free (error); - exit (1); - } - - g_option_context_free (opt_ctx); -} - -void -mm_options_set_debug (gboolean enabled) -{ - debug = enabled; -} - -gboolean -mm_options_debug (void) -{ - return debug; -} diff --git a/src/mm-options.h b/src/mm-options.h deleted file mode 100644 index ce33e274..00000000 --- a/src/mm-options.h +++ /dev/null @@ -1,23 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details: - * - * Copyright (C) 2008 Novell, Inc. - */ - -#ifndef MM_OPTIONS_H -#define MM_OPTIONS_H - -void mm_options_parse (int argc, char *argv[]); -void mm_options_set_debug (gboolean enabled); -gboolean mm_options_debug (void); - -#endif /* MM_OPTIONS_H */ diff --git a/src/mm-plugin-base.c b/src/mm-plugin-base.c index 5a86b977..8d32e2a5 100644 --- a/src/mm-plugin-base.c +++ b/src/mm-plugin-base.c @@ -36,6 +36,7 @@ #include "mm-utils.h" #include "libqcdm/src/commands.h" #include "libqcdm/src/utils.h" +#include "mm-log.h" static void plugin_init (MMPlugin *plugin_class); @@ -807,9 +808,9 @@ try_open (gpointer user_data) task_priv->full_id = g_signal_connect (task_priv->probe_port, "buffer-full", G_CALLBACK (port_buffer_full), task); - g_debug ("(%s): probe requested by plugin '%s'", - g_udev_device_get_name (port), - mm_plugin_get_name (MM_PLUGIN (task_priv->plugin))); + mm_dbg ("(%s): probe requested by plugin '%s'", + g_udev_device_get_name (port), + mm_plugin_get_name (MM_PLUGIN (task_priv->plugin))); mm_serial_port_flash (MM_SERIAL_PORT (task_priv->probe_port), 100, TRUE, flash_done, task); } diff --git a/src/mm-port.c b/src/mm-port.c index b2018fe2..a1291d0b 100644 --- a/src/mm-port.c +++ b/src/mm-port.c @@ -19,7 +19,7 @@ #include <string.h> #include "mm-port.h" -#include "mm-options.h" +#include "mm-log.h" G_DEFINE_TYPE (MMPort, mm_port, G_TYPE_OBJECT) @@ -47,6 +47,20 @@ typedef struct { /*****************************************************************************/ const char * +mm_port_subsys_to_name (MMPortSubsys psubsys) +{ + switch (psubsys) { + case MM_PORT_SUBSYS_TTY: + return "tty"; + case MM_PORT_SUBSYS_NET: + return "net"; + default: + break; + } + return "(unknown)"; +} + +const char * mm_port_type_to_name (MMPortType ptype) { switch (ptype) { @@ -161,16 +175,10 @@ mm_port_set_connected (MMPort *self, gboolean connected) if (priv->connected != connected) { priv->connected = connected; g_object_notify (G_OBJECT (self), MM_PORT_CONNECTED); - if (mm_options_debug()) { - GTimeVal tv; - - g_get_current_time (&tv); - g_debug ("<%ld.%ld> (%s): port now %s", - tv.tv_sec, - tv.tv_usec, - priv->device, - connected ? "connected" : "disconnected"); - } + + mm_dbg ("(%s): port now %s", + priv->device, + connected ? "connected" : "disconnected"); } } diff --git a/src/mm-port.h b/src/mm-port.h index 43f78f46..4bcffd49 100644 --- a/src/mm-port.h +++ b/src/mm-port.h @@ -78,5 +78,7 @@ void mm_port_set_connected (MMPort *self, gboolean connected); const char * mm_port_type_to_name (MMPortType ptype); +const char * mm_port_subsys_to_name (MMPortSubsys psubsys); + #endif /* MM_PORT_H */ diff --git a/src/mm-properties-changed-signal.c b/src/mm-properties-changed-signal.c index 633ff771..4408e80a 100644 --- a/src/mm-properties-changed-signal.c +++ b/src/mm-properties-changed-signal.c @@ -21,6 +21,7 @@ #include "mm-marshal.h" #include "mm-properties-changed-signal.h" #include "mm-properties-changed-glue.h" +#include "mm-log.h" #define DBUS_TYPE_G_MAP_OF_VARIANT (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)) #define DBUS_TYPE_G_ARRAY_OF_STRING (dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING)) @@ -150,10 +151,10 @@ properties_changed (gpointer data) { char buf[2048] = { 0, }; g_hash_table_foreach (props, add_to_string, &buf); - g_message ("%s: %s -> (%s) %s", __func__, - G_OBJECT_TYPE_NAME (object), - interface, - buf); + mm_dbg ("%s: %s -> (%s) %s", __func__, + G_OBJECT_TYPE_NAME (object), + interface, + buf); } #endif diff --git a/src/mm-qcdm-serial-port.c b/src/mm-qcdm-serial-port.c index 7f4302c5..e467f2a2 100644 --- a/src/mm-qcdm-serial-port.c +++ b/src/mm-qcdm-serial-port.c @@ -21,9 +21,9 @@ #include "mm-qcdm-serial-port.h" #include "mm-errors.h" -#include "mm-options.h" #include "libqcdm/src/com.h" #include "libqcdm/src/utils.h" +#include "mm-log.h" G_DEFINE_TYPE (MMQcdmSerialPort, mm_qcdm_serial_port, MM_TYPE_SERIAL_PORT) @@ -182,7 +182,6 @@ debug_log (MMSerialPort *port, const char *prefix, const char *buf, gsize len) { static GString *debug = NULL; const char *s = buf; - GTimeVal tv; if (!debug) debug = g_string_sized_new (512); @@ -192,12 +191,7 @@ debug_log (MMSerialPort *port, const char *prefix, const char *buf, gsize len) while (len--) g_string_append_printf (debug, " %02x", (guint8) (*s++ & 0xFF)); - g_get_current_time (&tv); - g_debug ("<%ld.%ld> (%s): %s", - tv.tv_sec, - tv.tv_usec, - mm_port_get_device (MM_PORT (port)), - debug->str); + mm_dbg ("(%s): %s", mm_port_get_device (MM_PORT (port)), debug->str); g_string_truncate (debug, 0); } diff --git a/src/mm-serial-parsers.c b/src/mm-serial-parsers.c index 735ebd97..75bcce4d 100644 --- a/src/mm-serial-parsers.c +++ b/src/mm-serial-parsers.c @@ -19,6 +19,7 @@ #include "mm-serial-parsers.h" #include "mm-errors.h" +#include "mm-log.h" /* Clean up the response by removing control characters like <CR><LF> etc */ static void @@ -174,7 +175,7 @@ mm_serial_parser_v0_parse (gpointer data, response_clean (response); if (local_error) { - g_debug ("Got failure code %d: %s", local_error->code, local_error->message); + mm_dbg ("Got failure code %d: %s", local_error->code, local_error->message); g_propagate_error (error, local_error); } @@ -336,7 +337,7 @@ done: response_clean (response); if (local_error) { - g_debug ("Got failure code %d: %s", local_error->code, local_error->message); + mm_dbg ("Got failure code %d: %s", local_error->code, local_error->message); g_propagate_error (error, local_error); } diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c index 0f4d888e..bf2a98ab 100644 --- a/src/mm-serial-port.c +++ b/src/mm-serial-port.c @@ -30,7 +30,7 @@ #include "mm-serial-port.h" #include "mm-errors.h" -#include "mm-options.h" +#include "mm-log.h" static gboolean mm_serial_port_queue_process (gpointer data); @@ -152,10 +152,10 @@ mm_serial_port_print_config (MMSerialPort *port, const char *detail) return; } - g_message ("*** %s (%s): (%s) baud rate: %d (%s)", - __func__, detail, mm_port_get_device (MM_PORT (port)), - stbuf.c_cflag & CBAUD, - baud_to_string (stbuf.c_cflag & CBAUD)); + mm_info ("(%s): (%s) baud rate: %d (%s)", + detail, mm_port_get_device (MM_PORT (port)), + stbuf.c_cflag & CBAUD, + baud_to_string (stbuf.c_cflag & CBAUD)); } #endif @@ -350,7 +350,7 @@ serial_debug (MMSerialPort *self, const char *prefix, const char *buf, gsize len { g_return_if_fail (len > 0); - if (mm_options_debug () && MM_SERIAL_PORT_GET_CLASS (self)->debug_log) + if (MM_SERIAL_PORT_GET_CLASS (self)->debug_log) MM_SERIAL_PORT_GET_CLASS (self)->debug_log (self, prefix, buf, len); } @@ -686,7 +686,6 @@ mm_serial_port_open (MMSerialPort *self, GError **error) MMSerialPortPrivate *priv; char *devfile; const char *device; - GTimeVal tv; struct serial_struct sinfo; g_return_val_if_fail (MM_IS_SERIAL_PORT (self), FALSE); @@ -700,12 +699,7 @@ mm_serial_port_open (MMSerialPort *self, GError **error) goto success; } - if (mm_options_debug ()) { - g_get_current_time (&tv); - g_debug ("<%ld.%ld> (%s) opening serial port...", - tv.tv_sec, tv.tv_usec, device); - } else - g_message ("(%s) opening serial port...", device); + mm_info ("(%s) opening serial port...", device); /* Only open a new file descriptor if we weren't given one already */ if (priv->fd < 0) { @@ -767,11 +761,7 @@ mm_serial_port_open (MMSerialPort *self, GError **error) success: priv->open_count++; - if (mm_options_debug ()) { - g_get_current_time (&tv); - g_debug ("<%ld.%ld> (%s) device open count is %d (open)", - tv.tv_sec, tv.tv_usec, device, priv->open_count); - } + mm_dbg ("(%s) device open count is %d (open)", device, priv->open_count); return TRUE; error: @@ -794,7 +784,6 @@ mm_serial_port_close (MMSerialPort *self) { MMSerialPortPrivate *priv; const char *device; - GTimeVal tv; int i; g_return_if_fail (MM_IS_SERIAL_PORT (self)); @@ -806,11 +795,7 @@ mm_serial_port_close (MMSerialPort *self) priv->open_count--; - if (mm_options_debug ()) { - g_get_current_time (&tv); - g_debug ("<%ld.%ld> (%s) device open count is %d (close)", - tv.tv_sec, tv.tv_usec, device, priv->open_count); - } + mm_dbg ("(%s) device open count is %d (close)", device, priv->open_count); if (priv->open_count > 0) return; @@ -823,12 +808,7 @@ mm_serial_port_close (MMSerialPort *self) if (priv->fd >= 0) { GTimeVal tv_start, tv_end; - g_get_current_time (&tv_start); - if (mm_options_debug ()) { - g_debug ("<%ld.%ld> (%s) closing serial port...", - tv_start.tv_sec, tv_start.tv_usec, device); - } else - g_message ("(%s) closing serial port...", device); + mm_info ("(%s) closing serial port...", device); mm_port_set_connected (MM_PORT (self), FALSE); @@ -842,16 +822,16 @@ mm_serial_port_close (MMSerialPort *self) mm_serial_port_flash_cancel (self); + g_get_current_time (&tv_start); + tcsetattr (priv->fd, TCSANOW, &priv->old_t); tcflush (priv->fd, TCIOFLUSH); close (priv->fd); priv->fd = -1; g_get_current_time (&tv_end); - if (mm_options_debug ()) { - g_debug ("<%ld.%ld> (%s) serial port closed", - tv_end.tv_sec, tv_end.tv_usec, device); - } + + mm_info ("(%s) serial port closed", device); /* Some ports don't respond to data and when close is called * the serial layer waits up to 30 second (closing_wait) for @@ -859,7 +839,7 @@ mm_serial_port_close (MMSerialPort *self) * Log that. See GNOME bug #630670 for more details. */ if (tv_end.tv_sec - tv_start.tv_sec > 20) - g_warning ("(%s): close blocked by driver for more than 20 seconds!", device); + mm_warn ("(%s): close blocked by driver for more than 20 seconds!", device); } /* Clear the command queue */ diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c index f0cbe61c..946916ff 100644 --- a/src/tests/test-modem-helpers.c +++ b/src/tests/test-modem-helpers.c @@ -17,6 +17,7 @@ #include <string.h> #include "mm-modem-helpers.h" +#include "mm-log.h" typedef struct { GPtrArray *solicited_creg; @@ -722,6 +723,16 @@ test_cgreg2_x220_unsolicited (void *f, gpointer d) } static void +test_creg2_s8500_wave_unsolicited (void *f, gpointer d) +{ + TestData *data = (TestData *) d; + const char *reply = "\r\n+CREG: 2,1,000B,2816, B, C2816\r\n"; + const CregResult result = { 1, 0x000B, 0x2816, 0, 7, FALSE}; + + test_creg_match ("Samsung Wave S8500 CREG=2", FALSE, reply, data, &result); +} + +static void test_cscs_icon225_support_response (void *f, gpointer d) { const char *reply = "\r\n+CSCS: (\"IRA\",\"GSM\",\"UCS2\")\r\n"; @@ -1069,8 +1080,7 @@ test_devid_item (void *f, gpointer d) item->gsn, item->revision, item->model, - item->manf, - FALSE); + item->manf); g_assert (devid); if (strcmp (devid, item->devid)) g_message ("%s", devid); @@ -1107,7 +1117,7 @@ test_cind_results (const char *desc, compare = g_hash_table_lookup (results, expected->desc); g_assert (compare); - g_assert_cmpint (i, ==, cind_response_get_index (compare)); + g_assert_cmpint (i + 1, ==, cind_response_get_index (compare)); g_assert_cmpint (expected->min, ==, cind_response_get_min (compare)); g_assert_cmpint (expected->max, ==, cind_response_get_max (compare)); } @@ -1168,6 +1178,15 @@ test_data_free (TestData *data) g_free (data); } +void +_mm_log (const char *loc, + const char *func, + guint32 level, + const char *fmt, + ...) +{ + /* Dummy log function */ +} #if GLIB_CHECK_VERSION(2,25,12) typedef GTestFixtureFunc TCFunc; @@ -1231,6 +1250,7 @@ int main (int argc, char **argv) g_test_suite_add (suite, TESTCASE (test_creg2_tm506_solicited, data)); g_test_suite_add (suite, TESTCASE (test_creg2_xu870_unsolicited_unregistered, data)); g_test_suite_add (suite, TESTCASE (test_creg2_md400_unsolicited, data)); + g_test_suite_add (suite, TESTCASE (test_creg2_s8500_wave_unsolicited, data)); g_test_suite_add (suite, TESTCASE (test_cgreg1_solicited, data)); g_test_suite_add (suite, TESTCASE (test_cgreg1_unsolicited, data)); diff --git a/src/tests/test-qcdm-serial-port.c b/src/tests/test-qcdm-serial-port.c index ab737c5e..3aeed6ab 100644 --- a/src/tests/test-qcdm-serial-port.c +++ b/src/tests/test-qcdm-serial-port.c @@ -31,6 +31,7 @@ #include "libqcdm/src/commands.h" #include "libqcdm/src/utils.h" #include "libqcdm/src/com.h" +#include "mm-log.h" typedef struct { int master; @@ -449,10 +450,14 @@ typedef void (*TCFunc)(void); #define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL) #define TESTCASE_PTY(t, d) g_test_create_case (#t, sizeof (*d), d, (TCFunc) test_pty_create, (TCFunc) t, (TCFunc) test_pty_cleanup) -gboolean mm_options_debug (void); -gboolean mm_options_debug (void) +void +_mm_log (const char *loc, + const char *func, + guint32 level, + const char *fmt, + ...) { - return g_test_verbose (); + /* Dummy log function */ } int main (int argc, char **argv) diff --git a/test/ussd.py b/test/ussd.py index 332cc172..2040f12e 100644..100755 --- a/test/ussd.py +++ b/test/ussd.py @@ -15,7 +15,7 @@ # # Usage: ./test/ussd.py /org/freedesktop/ModemManager/Modems/0 '*130#' -import sys, dbus +import sys, dbus, re MM_DBUS_SERVICE='org.freedesktop.ModemManager' MM_DBUS_INTERFACE_USSD='org.freedesktop.ModemManager.Modem.Gsm.Ussd' @@ -23,5 +23,22 @@ MM_DBUS_INTERFACE_USSD='org.freedesktop.ModemManager.Modem.Gsm.Ussd' bus = dbus.SystemBus() proxy = bus.get_object(MM_DBUS_SERVICE, sys.argv[1]) modem = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_USSD) -ret = modem.Initiate (sys.argv[2]) + +if len(sys.argv) != 3: + print "Usage: %s dbus_object ussd" + sys.exit(1) +else: + arg = sys.argv[2] + +# For testing purposes treat all "common" USSD sequences as initiate and the +# rest (except for cancel) as response. See GSM 02.90. +initiate_re = re.compile('[*#]{1,3}1[0-9][0-9].*#') + +if initiate_re.match(arg): + ret = modem.Initiate(arg) +elif arg == "cancel": + ret = modem.Cancel() +else: + ret = modem.Respond(arg) print ret + |