qmidms: add DMS, with first call (get_ids)

BUG=chromium-os:27303
TEST=will come later

Change-Id: Ia85cc4873889e624deeb3267bc08c1e676485260
diff --git a/include/libqmi.h b/include/libqmi.h
index f435ad8..ca7cad4 100644
--- a/include/libqmi.h
+++ b/include/libqmi.h
@@ -779,12 +779,12 @@
   void *context);
 
 /**
- * Callback type for qmidev_get_serial_numbers.
+ * Callback type for qmidev_get_ids.
  * @esn: Electronic Serial Number,
  * @imei: International Mobile Equipment Identifier
  * @meid: Mobile Equipment Identifier
  */
-typedef void (*qmidev_serial_numbers_response_fn)(
+typedef void (*qmidev_get_ids_response_fn)(
   qmidev *dev,
   void *context,
   int status,
@@ -793,9 +793,9 @@
   const char *meid);
 
 /* Gets the serial numbers of the device. */
-int qmidev_get_serial_numbers(
+int qmidev_get_ids(
   qmidev *dev,
-  qmidev_serial_numbers_response_fn callback,
+  qmidev_get_ids_response_fn callback,
   void *context);
 
 /* TODO: enums */
diff --git a/src/Makefile b/src/Makefile
index ae4ed1e..b57e48e 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -14,6 +14,7 @@
 	qmi.c \
 	qmictl.c \
 	qmidev.c \
+	qmidms.c \
 	qmimsg.c \
 	util.c
 UNITTESTS = \
diff --git a/src/qmidms.c b/src/qmidms.c
new file mode 100644
index 0000000..ccc3f1d
--- /dev/null
+++ b/src/qmidms.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * qmidms: QMI calls on the DMS (Device Management Service) interface
+ *
+ * Sources used in writing this file (see README for links):
+ * [GobiNet]/QMI.c
+ * [GobiNet]/QMIDevice.c
+ * [cros-kerne]/drivers/net/usb/gobi/qmi.c
+ * [cros-kerne]/drivers/net/usb/gobi/qmidevice.c
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <glib.h>
+
+#include <libqmi.h>
+
+#include "qmi.h"
+#include "qmidev.h"
+#include "qmimsg.h"
+
+enum {
+  QMIDMS_MSG_GET_IDS = 37
+};
+
+enum {
+  QMIDMS_TLV_GET_IDS_ESN = 0x10,
+  QMIDMS_TLV_GET_IDS_IMEI,
+  QMIDMS_TLV_GET_IDS_MEID
+};
+
+struct get_ids_context {
+  qmidev_get_ids_response_fn caller_callback;
+  void *caller_context;
+};
+
+static void got_ids(struct qmidev *qmidev,
+                   void *data,
+                   int status,
+                   struct qmimsg *message)
+{
+  assert(qmidev);
+  assert(data);
+  assert(message);
+
+  struct get_ids_context *context = data;
+  int result;
+
+  char *esn = NULL, *imei = NULL, *meid = NULL;
+
+  if (status) {
+    result = status;
+    goto out;
+  }
+
+  qmi_tlv_strdup(message, QMIDMS_TLV_GET_IDS_ESN,  NULL, &esn);
+  qmi_tlv_strdup(message, QMIDMS_TLV_GET_IDS_IMEI, NULL, &imei);
+  qmi_tlv_strdup(message, QMIDMS_TLV_GET_IDS_MEID, NULL, &meid);
+
+  result = 0;
+
+out:
+  context->caller_callback(qmidev, context->caller_context, result,
+                           esn, imei, meid);
+  g_free(esn);
+  g_free(imei);
+  g_free(meid);
+  g_slice_free(struct get_ids_context, context);
+}
+
+int qmidev_get_ids(struct qmidev *qmidev,
+                   qmidev_get_ids_response_fn caller_callback,
+                   void *caller_context)
+{
+  int result;
+
+  struct get_ids_context *context = g_slice_new(struct get_ids_context);
+  context->caller_callback = caller_callback;
+  context->caller_context  = caller_context;
+
+  struct qmimsg *message;
+  result = qmidev_make_request(qmidev, QMI_SVC_DMS, QMIDMS_MSG_GET_IDS,
+                               &message);
+  if (result)
+    goto fail;
+
+  result = qmidev_send_request(qmidev, message,
+                               QMIDMS_MSG_GET_IDS,
+                               &got_ids, context);
+  if (result)
+    goto fail;
+
+  return 0;
+
+fail:
+  g_slice_free(struct get_ids_context, context);
+  return result;
+}