diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-generic-gsm.c | 40 | ||||
-rw-r--r-- | src/mm-plugin-base.c | 55 | ||||
-rw-r--r-- | src/mm-serial-port.c | 27 | ||||
-rw-r--r-- | src/mm-serial-port.h | 4 |
4 files changed, 105 insertions, 21 deletions
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index 81bf26b1..f6e97c3f 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -157,21 +157,22 @@ typedef struct { } CPinResult; static CPinResult unlock_results[] = { - { "SIM PIN", "sim-pin", MM_MOBILE_ERROR_SIM_PIN }, - { "SIM PUK", "sim-puk", MM_MOBILE_ERROR_SIM_PUK }, - { "PH-SIM PIN", "ph-sim-pin", MM_MOBILE_ERROR_PH_SIM_PIN }, + /* Longer entries first so we catch the correct one with strcmp() */ + { "PH-NETSUB PIN", "ph-netsub-pin", MM_MOBILE_ERROR_NETWORK_SUBSET_PIN }, + { "PH-NETSUB PUK", "ph-netsub-puk", MM_MOBILE_ERROR_NETWORK_SUBSET_PUK }, { "PH-FSIM PIN", "ph-fsim-pin", MM_MOBILE_ERROR_PH_FSIM_PIN }, { "PH-FSIM PUK", "ph-fsim-puk", MM_MOBILE_ERROR_PH_FSIM_PUK }, - { "SIM PIN2", "sim-pin2", MM_MOBILE_ERROR_SIM_PIN2 }, - { "SIM PUK2", "sim-puk2", MM_MOBILE_ERROR_SIM_PUK2 }, + { "PH-CORP PIN", "ph-corp-pin", MM_MOBILE_ERROR_CORP_PIN }, + { "PH-CORP PUK", "ph-corp-puk", MM_MOBILE_ERROR_CORP_PUK }, + { "PH-SIM PIN", "ph-sim-pin", MM_MOBILE_ERROR_PH_SIM_PIN }, { "PH-NET PIN", "ph-net-pin", MM_MOBILE_ERROR_NETWORK_PIN }, { "PH-NET PUK", "ph-net-puk", MM_MOBILE_ERROR_NETWORK_PUK }, - { "PH-NETSUB PIN", "ph-netsub-pin", MM_MOBILE_ERROR_NETWORK_SUBSET_PIN }, - { "PH-NETSUB PUK", "ph-netsub-puk", MM_MOBILE_ERROR_NETWORK_SUBSET_PUK }, { "PH-SP PIN", "ph-sp-pin", MM_MOBILE_ERROR_SERVICE_PIN }, { "PH-SP PUK", "ph-sp-puk", MM_MOBILE_ERROR_SERVICE_PUK }, - { "PH-CORP PIN", "ph-corp-pin", MM_MOBILE_ERROR_CORP_PIN }, - { "PH-CORP PUK", "ph-corp-puk", MM_MOBILE_ERROR_CORP_PUK }, + { "SIM PIN2", "sim-pin2", MM_MOBILE_ERROR_SIM_PIN2 }, + { "SIM PUK2", "sim-puk2", MM_MOBILE_ERROR_SIM_PUK2 }, + { "SIM PIN", "sim-pin", MM_MOBILE_ERROR_SIM_PIN }, + { "SIM PUK", "sim-puk", MM_MOBILE_ERROR_SIM_PUK }, { NULL, NULL, MM_MOBILE_ERROR_PHONE_FAILURE }, }; @@ -665,11 +666,18 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self, g_return_if_fail (MM_IS_GENERIC_GSM (self)); g_return_if_fail (info != NULL); + priv = MM_GENERIC_GSM_GET_PRIVATE (self); + if (error) { mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_DISABLED, MM_MODEM_STATE_REASON_NONE); + if (priv->primary && mm_serial_port_is_open (priv->primary)) + mm_serial_port_close (priv->primary); + if (priv->secondary && mm_serial_port_is_open (priv->secondary)) + mm_serial_port_close (priv->secondary); + info->error = g_error_copy (error); mm_callback_info_schedule (info); return; @@ -678,8 +686,6 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self, mm_generic_gsm_update_enabled_state (self, FALSE, MM_MODEM_STATE_REASON_NONE); } - priv = MM_GENERIC_GSM_GET_PRIVATE (self); - /* Open the second port here if the modem has one. We'll use it for * signal strength and registration updates when the device is connected, * but also many devices will send unsolicited registration or other @@ -1965,13 +1971,19 @@ disconnect_flash_done (MMSerialPort *port, char *command; info->error = mm_modem_check_removed (info->modem, error); - if (info->error) { + /* Ignore NO_CARRIER errors and proceed with the PDP context deactivation */ + if ( info->error + && !g_error_matches (info->error, + MM_MODEM_CONNECT_ERROR, + MM_MODEM_CONNECT_ERROR_NO_CARRIER)) { mm_callback_info_schedule (info); return; } - /* Disconnect the PDP context */ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); + mm_port_set_connected (priv->data, FALSE); + + /* Disconnect the PDP context */ if (priv->cid >= 0) command = g_strdup_printf ("+CGACT=0,%d", priv->cid); else { @@ -1979,7 +1991,7 @@ disconnect_flash_done (MMSerialPort *port, command = g_strdup_printf ("+CGACT=0"); } - mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), command, 60, disconnect_cgact_done, info); + mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), command, 3, disconnect_cgact_done, info); g_free (command); } diff --git a/src/mm-plugin-base.c b/src/mm-plugin-base.c index da24e840..7547fe21 100644 --- a/src/mm-plugin-base.c +++ b/src/mm-plugin-base.c @@ -77,6 +77,8 @@ typedef enum { PROBE_STATE_LAST } ProbeState; +static void probe_complete (MMPluginBaseSupportsTask *task); + /*****************************************************************************/ G_DEFINE_TYPE (MMPluginBaseSupportsTask, mm_plugin_base_supports_task, G_TYPE_OBJECT) @@ -91,6 +93,7 @@ typedef struct { guint open_id; guint32 open_tries; + guint full_id; MMAtSerialPort *probe_port; guint32 probed_caps; @@ -198,6 +201,11 @@ mm_plugin_base_supports_task_complete (MMPluginBaseSupportsTask *task, priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (task); g_return_if_fail (priv->callback != NULL); + if (priv->full_id) { + g_source_remove (priv->full_id); + priv->full_id = 0; + } + subsys = g_udev_device_get_subsystem (priv->port); name = g_udev_device_get_name (priv->port); @@ -251,11 +259,15 @@ supports_task_dispose (GObject *object) if (priv->open_id) g_source_remove (priv->open_id); + if (priv->full_id) + g_source_remove (priv->full_id); if (priv->probe_id) g_source_remove (priv->probe_id); - if (priv->probe_port) + if (priv->probe_port) { + mm_serial_port_close (priv->probe_port); g_object_unref (priv->probe_port); + } G_OBJECT_CLASS (mm_plugin_base_supports_task_parent_class)->dispose (object); } @@ -349,6 +361,44 @@ parse_cgmm (const char *buf) return 0; } +static const char *dq_strings[] = { + "option/faema_", "os_logids.h", NULL +}; + +static void +port_buffer_full (MMSerialPort *port, GString *buffer, gpointer user_data) +{ + MMPluginBaseSupportsTask *task = MM_PLUGIN_BASE_SUPPORTS_TASK (user_data); + MMPluginBaseSupportsTaskPrivate *priv = MM_PLUGIN_BASE_SUPPORTS_TASK_GET_PRIVATE (user_data); + const char **iter; + size_t iter_len; + int i; + + /* Check for an immediate disqualification response. There are some + * ports (Option Icera-based chipsets have them, as do Qualcomm Gobi + * devices before their firmware is loaded) that just shouldn't be + * probed if we get a certain response because we know they can't be + * used. Kernel bugs (at least with 2.6.31 and 2.6.32) also trigger port + * flow control kernel oopses if we read too much data for these ports. + */ + + for (iter = &dq_strings[0]; iter && *iter; iter++) { + /* Search in the response for the item; the response could have embedded + * nulls so we can't use memcmp() or strstr() on the whole response. + */ + iter_len = strlen (*iter); + for (i = 0; i < buffer->len - iter_len; i++) { + if (!memcmp (&buffer->str[i], *iter, iter_len)) { + /* Immediately close the port and complete probing */ + priv->probed_caps = 0; + mm_serial_port_close (priv->probe_port); + probe_complete (task); + return; + } + } + } +} + static gboolean emit_probe_result (gpointer user_data) { @@ -626,6 +676,9 @@ try_open (gpointer user_data) port = mm_plugin_base_supports_task_get_port (task); g_assert (port); + 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))); diff --git a/src/mm-serial-port.c b/src/mm-serial-port.c index 210ce2e6..29505a21 100644 --- a/src/mm-serial-port.c +++ b/src/mm-serial-port.c @@ -629,9 +629,13 @@ data_available (GIOChannel *source, status = g_io_channel_read_chars (source, buf, SERIAL_BUF_SIZE, &bytes_read, &err); if (status == G_IO_STATUS_ERROR) { - g_warning ("%s", err->message); - g_error_free (err); - err = NULL; + if (err && err->message) + g_warning ("%s", err->message); + g_clear_error (&err); + + /* Serial port is closed; we're done */ + if (priv->watch_id == 0) + break; } /* If no bytes read, just let g_io_channel wait for more data */ @@ -644,9 +648,9 @@ data_available (GIOChannel *source, } /* Make sure the response doesn't grow too long */ - if (priv->response->len > SERIAL_BUF_SIZE) { - g_warning ("%s (%s): response buffer filled before repsonse received", - G_STRFUNC, mm_port_get_device (MM_PORT (self))); + if (priv->response->len > SERIAL_BUF_SIZE) { + /* Notify listeners and then trim the buffer */ + g_signal_emit_by_name (self, "buffer-full", priv->response); g_byte_array_remove_range (priv->response, 0, (SERIAL_BUF_SIZE / 2)); } @@ -789,6 +793,7 @@ mm_serial_port_close (MMSerialPort *self) if (priv->channel) { g_source_remove (priv->watch_id); + priv->watch_id = 0; g_io_channel_shutdown (priv->channel, TRUE, NULL); g_io_channel_unref (priv->channel); priv->channel = NULL; @@ -1238,4 +1243,14 @@ mm_serial_port_class_init (MMSerialPortClass *klass) "Send delay", 0, G_MAXUINT64, 0, G_PARAM_READWRITE)); + + /* Signals */ + g_signal_new ("buffer-full", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MMSerialPortClass, buffer_full), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); } + diff --git a/src/mm-serial-port.h b/src/mm-serial-port.h index c07d70c8..6835d8bf 100644 --- a/src/mm-serial-port.h +++ b/src/mm-serial-port.h @@ -50,6 +50,7 @@ struct _MMSerialPort { struct _MMSerialPortClass { MMPortClass parent; +<<<<<<< HEAD /* Called for subclasses to parse unsolicited responses. If any recognized * unsolicited response is found, it should be removed from the 'response' * byte array before returning. @@ -80,6 +81,9 @@ struct _MMSerialPortClass { * return FALSE and set 'error' as appropriate. */ gboolean (*config_fd) (MMSerialPort *self, int fd, GError **error); + + /* Signals */ + void (*buffer_full) (MMSerialPort *port, const GByteArray *buffer); }; GType mm_serial_port_get_type (void); |