Merge remote-tracking branch 'cros/upstream' into 'cros/master'
Change-Id: Ibb43d893d888a424cee14728613dabebd41e82d9
diff --git a/docs/reference/libqmi-glib/libqmi-glib-common.sections b/docs/reference/libqmi-glib/libqmi-glib-common.sections
index 5258c1e..d194120 100644
--- a/docs/reference/libqmi-glib/libqmi-glib-common.sections
+++ b/docs/reference/libqmi-glib/libqmi-glib-common.sections
@@ -48,6 +48,7 @@
QMI_DEVICE_PROXY_PATH
QMI_DEVICE_WWAN_IFACE
QMI_DEVICE_SIGNAL_INDICATION
+QMI_DEVICE_SIGNAL_REMOVED
QmiDevice
QmiDeviceOpenFlags
QmiDeviceReleaseClientFlags
diff --git a/src/libqmi-glib/qmi-device.c b/src/libqmi-glib/qmi-device.c
index 841bcb4..e98f3ca 100644
--- a/src/libqmi-glib/qmi-device.c
+++ b/src/libqmi-glib/qmi-device.c
@@ -76,6 +76,7 @@
enum {
SIGNAL_INDICATION,
+ SIGNAL_REMOVED,
SIGNAL_LAST
};
@@ -1555,13 +1556,14 @@
g_error_free (error);
/* Close the device */
qmi_device_close (self, NULL);
- return FALSE;
+ return G_SOURCE_REMOVE;
}
if (r == 0) {
/* HUP! */
g_warning ("Cannot read from istream: connection broken");
- return FALSE;
+ g_signal_emit (self, signals[SIGNAL_REMOVED], 0);
+ return G_SOURCE_REMOVE;
}
/* else, r > 0 */
@@ -1571,7 +1573,7 @@
parse_response (self);
- return TRUE;
+ return G_SOURCE_CONTINUE;
}
typedef struct {
@@ -1623,7 +1625,6 @@
self,
NULL);
g_source_attach (self->priv->input_source, g_main_context_get_thread_default ());
- g_source_unref (self->priv->input_source);
g_task_return_boolean (task, TRUE);
g_object_unref (task);
@@ -2407,7 +2408,10 @@
static void
destroy_iostream (QmiDevice *self)
{
- g_clear_pointer (&self->priv->input_source, g_source_destroy);
+ if (self->priv->input_source) {
+ g_source_destroy (self->priv->input_source);
+ g_clear_pointer (&self->priv->input_source, g_source_unref);
+ }
g_clear_pointer (&self->priv->buffer, g_byte_array_unref);
g_clear_object (&self->priv->istream);
g_clear_object (&self->priv->ostream);
@@ -3174,4 +3178,24 @@
G_TYPE_NONE,
1,
G_TYPE_BYTE_ARRAY);
+
+ /**
+ * QmiDevice::device-removed:
+ * @object: A #QmiDevice.
+ * @output: none
+ *
+ * The ::device-removed signal is emitted when an unexpected port hang-up is received.
+ *
+ * Since: 1.20
+ */
+ signals[SIGNAL_REMOVED] =
+ g_signal_new (QMI_DEVICE_SIGNAL_REMOVED,
+ G_OBJECT_CLASS_TYPE (G_OBJECT_CLASS (klass)),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 0);
}
diff --git a/src/libqmi-glib/qmi-device.h b/src/libqmi-glib/qmi-device.h
index 8ff2318..4ece41b 100644
--- a/src/libqmi-glib/qmi-device.h
+++ b/src/libqmi-glib/qmi-device.h
@@ -105,6 +105,15 @@
#define QMI_DEVICE_SIGNAL_INDICATION "indication"
/**
+ * QMI_DEVICE_REMOVED:
+ *
+ * Symbol defining the #QmiDevice::device-removed signal.
+ *
+ * Since: 1.20
+ */
+#define QMI_DEVICE_SIGNAL_REMOVED "device-removed"
+
+/**
* QmiDevice:
*
* The #QmiDevice structure contains private data and should only be accessed
diff --git a/src/libqmi-glib/qmi-proxy.c b/src/libqmi-glib/qmi-proxy.c
index 0e19cd8..bfb362e 100644
--- a/src/libqmi-glib/qmi-proxy.c
+++ b/src/libqmi-glib/qmi-proxy.c
@@ -98,6 +98,7 @@
QmiMessage *internal_proxy_open_request;
GArray *qmi_client_info_array;
guint indication_id;
+ guint device_removed_id;
} Client;
static gboolean connection_readable_cb (GSocket *socket, GIOCondition condition, Client *client);
@@ -131,6 +132,8 @@
if (client->device) {
if (g_signal_handler_is_connected (client->device, client->indication_id))
g_signal_handler_disconnect (client->device, client->indication_id);
+ if (g_signal_handler_is_connected (client->device, client->device_removed_id))
+ g_signal_handler_disconnect (client->device, client->device_removed_id);
g_object_unref (client->device);
}
@@ -322,6 +325,13 @@
}
static void
+device_removed_cb (QmiDevice *device,
+ Client *client)
+{
+ untrack_client (client->proxy, client);
+}
+
+static void
device_open_ready (QmiDevice *device,
GAsyncResult *res,
Client *client)
@@ -355,6 +365,10 @@
"indication",
G_CALLBACK (indication_cb),
client);
+ client->device_removed_id = g_signal_connect (client->device,
+ "device-removed",
+ G_CALLBACK (device_removed_cb),
+ client);
complete_internal_proxy_open (self, client);
diff --git a/src/qmicli/qmicli-uim.c b/src/qmicli/qmicli-uim.c
index 84df534..ce39e2d 100644
--- a/src/qmicli/qmicli-uim.c
+++ b/src/qmicli/qmicli-uim.c
@@ -43,6 +43,7 @@
/* Options */
static gchar *read_transparent_str;
+static gchar *read_record_str;
static gchar *set_pin_protection_str;
static gchar *verify_pin_str;
static gchar *unblock_pin_str;
@@ -80,6 +81,10 @@
"Get the attributes of a given file",
"[0xNNNN,0xNNNN,...]"
},
+ { "uim-read-record", 0, 0, G_OPTION_ARG_STRING, &read_record_str,
+ "Read a record from given file (allowed keys: record-number, record-length, file ([0xNNNN-0xNNNN,...])",
+ "[\"key=value,...\"]"
+ },
{ "uim-get-card-status", 0, 0, G_OPTION_ARG_NONE, &get_card_status_flag,
"Get card status",
NULL
@@ -136,6 +141,7 @@
!!unblock_pin_str +
!!change_pin_str +
!!read_transparent_str +
+ !!read_record_str +
!!get_file_attributes_str +
!!sim_power_on_str +
!!sim_power_off_str +
@@ -865,14 +871,15 @@
}
static gboolean
-get_sim_file_id_and_path (const gchar *file_path_str,
- guint16 *file_id,
- GArray **file_path)
+get_sim_file_id_and_path_with_separator (const gchar *file_path_str,
+ guint16 *file_id,
+ GArray **file_path,
+ const gchar *separator)
{
guint i;
gchar **split;
- split = g_strsplit (file_path_str, ",", -1);
+ split = g_strsplit (file_path_str, separator, -1);
if (!split) {
g_printerr ("error: invalid file path given: '%s'\n", file_path_str);
return FALSE;
@@ -914,6 +921,14 @@
return TRUE;
}
+static gboolean
+get_sim_file_id_and_path (const gchar *file_path_str,
+ guint16 *file_id,
+ GArray **file_path)
+{
+ return get_sim_file_id_and_path_with_separator (file_path_str, file_id, file_path, ",");
+}
+
static void
read_transparent_ready (QmiClientUim *client,
GAsyncResult *res)
@@ -1013,6 +1028,175 @@
}
static void
+read_record_ready (QmiClientUim *client,
+ GAsyncResult *res)
+{
+ QmiMessageUimReadRecordOutput *output;
+ GError *error = NULL;
+ guint8 sw1 = 0;
+ guint8 sw2 = 0;
+ GArray *read_result = NULL;
+
+ output = qmi_client_uim_read_record_finish (client, res, &error);
+ if (!output) {
+ g_printerr ("error: operation failed: %s\n", error->message);
+ g_error_free (error);
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ if (!qmi_message_uim_read_record_output_get_result (output, &error)) {
+ g_printerr ("error: couldn't read record file from the UIM: %s\n", error->message);
+ g_error_free (error);
+
+ /* Card result */
+ if (qmi_message_uim_read_record_output_get_card_result (
+ output,
+ &sw1,
+ &sw2,
+ NULL)) {
+ g_print ("Card result:\n"
+ "\tSW1: '0x%02x'\n"
+ "\tSW2: '0x%02x'\n",
+ sw1, sw2);
+ }
+
+ qmi_message_uim_read_record_output_unref (output);
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ g_print ("[%s] Successfully read information from the UIM:\n",
+ qmi_device_get_path_display (ctx->device));
+
+ /* Card result */
+ if (qmi_message_uim_read_record_output_get_card_result (
+ output,
+ &sw1,
+ &sw2,
+ NULL)) {
+ g_print ("Card result:\n"
+ "\tSW1: '0x%02x'\n"
+ "\tSW2: '0x%02x'\n",
+ sw1, sw2);
+ }
+
+ /* Read result */
+ if (qmi_message_uim_read_record_output_get_read_result (
+ output,
+ &read_result,
+ NULL)) {
+ gchar *str;
+
+ str = qmicli_get_raw_data_printable (read_result, 80, "\t");
+ g_print ("Read result:\n"
+ "%s\n",
+ str);
+ g_free (str);
+ }
+
+ qmi_message_uim_read_record_output_unref (output);
+ operation_shutdown (TRUE);
+}
+
+typedef struct {
+ char *file;
+ guint16 record_number;
+ guint16 record_length;
+} SetReadRecordProperties;
+
+static gboolean
+set_read_record_properties_handle (const gchar *key,
+ const gchar *value,
+ GError **error,
+ gpointer user_data)
+{
+ SetReadRecordProperties *props = (SetReadRecordProperties *) user_data;
+
+ if (!value || !value[0]) {
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "key '%s' requires a value",
+ key);
+ return FALSE;
+ }
+
+ if (g_ascii_strcasecmp (key, "file") == 0) {
+ props->file = strdup(value);
+ return TRUE;
+ }
+
+ if (g_ascii_strcasecmp (key, "record-number") == 0) {
+ props->record_number = (guint16) atoi(value);
+ return TRUE;
+ }
+
+ if (g_ascii_strcasecmp (key, "record-length") == 0) {
+ props->record_length = (guint16) atoi(value);
+ return TRUE;
+ }
+
+ g_set_error (error,
+ QMI_CORE_ERROR,
+ QMI_CORE_ERROR_FAILED,
+ "Unrecognized option '%s'",
+ key);
+ return FALSE;
+}
+
+static QmiMessageUimReadRecordInput *
+read_record_input_create (const gchar *str)
+{
+ GError *error = NULL;
+ QmiMessageUimReadRecordInput *input = NULL;
+ SetReadRecordProperties props = {
+ .file = NULL,
+ .record_number = 0,
+ .record_length = 0,
+ };
+ guint16 file_id = 0;
+ GArray *file_path = NULL;
+
+ if (!qmicli_parse_key_value_string (str,
+ &error,
+ set_read_record_properties_handle,
+ &props)) {
+ g_printerr ("error: could not parse input string '%s': %s\n",
+ str,
+ error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ if (!get_sim_file_id_and_path_with_separator (props.file, &file_id, &file_path, "-"))
+ goto out;
+
+ input = qmi_message_uim_read_record_input_new ();
+
+ qmi_message_uim_read_record_input_set_session_information (
+ input,
+ QMI_UIM_SESSION_TYPE_PRIMARY_GW_PROVISIONING,
+ "",
+ NULL);
+ qmi_message_uim_read_record_input_set_file (
+ input,
+ file_id,
+ file_path,
+ NULL);
+ qmi_message_uim_read_record_input_set_record (
+ input,
+ props.record_number,
+ props.record_length,
+ NULL);
+
+out:
+ free (props.file);
+ g_array_unref (file_path);
+ return input;
+}
+
+static void
get_file_attributes_ready (QmiClientUim *client,
GAsyncResult *res,
gchar *file_name)
@@ -1293,6 +1477,28 @@
return;
}
+ /* Request to read a transparent file? */
+ if (read_record_str) {
+ QmiMessageUimReadRecordInput *input;
+
+ input = read_record_input_create (read_record_str);
+ if (!input) {
+ operation_shutdown (FALSE);
+ return;
+ }
+
+ g_debug ("Asynchronously reading record file at '%s'...",
+ read_record_str);
+ qmi_client_uim_read_record (ctx->client,
+ input,
+ 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)read_record_ready,
+ NULL);
+ qmi_message_uim_read_record_input_unref (input);
+ return;
+ }
+
/* Request to get file attributes? */
if (get_file_attributes_str) {
QmiMessageUimGetFileAttributesInput *input;