Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / profiles / deviceinfo / deviceinfo.c
index a0e9951..d1f51a0 100644 (file)
@@ -3,6 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2012 Texas Instruments, Inc.
+ *  Copyright (C) 2015 Google Inc.
  *
  *  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
 #include "src/device.h"
 #include "src/profile.h"
 #include "src/service.h"
-#include "src/shared/util.h"
 #include "attrib/gattrib.h"
-#include "src/attio.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"
 #include "attrib/att.h"
-#include "attrib/gatt.h"
 #include "src/log.h"
 
 #define PNP_ID_SIZE    7
 
-struct deviceinfo {
-       struct btd_device       *dev;           /* Device reference */
-       GAttrib                 *attrib;        /* GATT connection */
-       guint                   attioid;        /* Att watcher id */
-       struct att_range        *svc_range;     /* DeviceInfo range */
-       GSList                  *chars;         /* Characteristics */
-};
-
-struct characteristic {
-       struct gatt_char        attr;   /* Characteristic */
-       struct deviceinfo       *d;     /* deviceinfo where the char belongs */
-};
-
-static void deviceinfo_driver_remove(struct btd_service *service)
+static void read_pnpid_cb(bool success, uint8_t att_ecode, const uint8_t *value,
+                                       uint16_t length, void *user_data)
 {
-       struct deviceinfo *d = btd_service_get_user_data(service);
-
-       if (d->attioid > 0)
-               btd_device_remove_attio_callback(d->dev, d->attioid);
-
-       if (d->attrib != NULL)
-               g_attrib_unref(d->attrib);
-
-       g_slist_free_full(d->chars, g_free);
+       struct btd_device *device = user_data;
 
-       btd_device_unref(d->dev);
-       g_free(d->svc_range);
-       g_free(d);
-}
-
-static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
-                                                       gpointer user_data)
-{
-       struct characteristic *ch = user_data;
-       uint8_t value[PNP_ID_SIZE];
-       ssize_t vlen;
-
-       if (status != 0) {
-               error("Error reading PNP_ID value: %s", att_ecode2str(status));
+       if (!success) {
+               error("Error reading PNP_ID value: %s",
+                                               att_ecode2str(att_ecode));
                return;
        }
 
-       vlen = dec_read_resp(pdu, len, value, sizeof(value));
-       if (vlen < 0) {
-               error("Error reading PNP_ID: Protocol error");
-               return;
-       }
-
-       if (vlen < 7) {
+       if (length < PNP_ID_SIZE) {
                error("Error reading PNP_ID: Invalid pdu length received");
                return;
        }
 
-       btd_device_set_pnpid(ch->d->dev, value[0], get_le16(&value[1]),
+       btd_device_set_pnpid(device, value[0], get_le16(&value[1]),
                                get_le16(&value[3]), get_le16(&value[5]));
 }
 
-static void process_deviceinfo_char(struct characteristic *ch)
+static void handle_pnpid(struct btd_device *device, uint16_t value_handle)
 {
-       if (g_strcmp0(ch->attr.uuid, PNPID_UUID) == 0)
-               gatt_read_char(ch->d->attrib, ch->attr.value_handle,
-                                                       read_pnpid_cb, ch);
+       struct bt_gatt_client *client = btd_device_get_gatt_client(device);
+
+       if (!bt_gatt_client_read_value(client, value_handle,
+                                               read_pnpid_cb, device, NULL))
+               DBG("Failed to send request to read pnpid");
 }
 
-static void configure_deviceinfo_cb(uint8_t status, GSList *characteristics,
+static void handle_characteristic(struct gatt_db_attribute *attr,
                                                                void *user_data)
 {
-       struct deviceinfo *d = user_data;
-       GSList *l;
+       struct btd_device *device = user_data;
+       uint16_t value_handle;
+       bt_uuid_t uuid, pnpid_uuid;
+
+       bt_string_to_uuid(&pnpid_uuid, PNPID_UUID);
 
-       if (status != 0) {
-               error("Discover deviceinfo characteristics: %s",
-                                                       att_ecode2str(status));
+       if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, NULL,
+                                                               &uuid)) {
+               error("Failed to obtain characteristic data");
                return;
        }
 
-       for (l = characteristics; l; l = l->next) {
-               struct gatt_char *c = l->data;
-               struct characteristic *ch;
+       if (bt_uuid_cmp(&pnpid_uuid, &uuid) == 0)
+               handle_pnpid(device, value_handle);
+       else {
+               char uuid_str[MAX_LEN_UUID_STR];
 
-               ch = g_new0(struct characteristic, 1);
-               ch->attr.handle = c->handle;
-               ch->attr.properties = c->properties;
-               ch->attr.value_handle = c->value_handle;
-               memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
-               ch->d = d;
-
-               d->chars = g_slist_append(d->chars, ch);
-
-               process_deviceinfo_char(ch);
+               bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
+               DBG("Unsupported characteristic: %s", uuid_str);
        }
 }
-static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
-{
-       struct deviceinfo *d = user_data;
 
-       d->attrib = g_attrib_ref(attrib);
+static void foreach_deviceinfo_service(struct gatt_db_attribute *attr,
+                                                               void *user_data)
+{
+       struct btd_device *device = user_data;
 
-       gatt_discover_char(d->attrib, d->svc_range->start, d->svc_range->end,
-                                       NULL, configure_deviceinfo_cb, d);
+       gatt_db_service_foreach_char(attr, handle_characteristic, device);
 }
 
-static void attio_disconnected_cb(gpointer user_data)
+static int deviceinfo_driver_probe(struct btd_service *service)
 {
-       struct deviceinfo *d = user_data;
-
-       g_attrib_unref(d->attrib);
-       d->attrib = NULL;
+       return 0;
 }
 
-static int deviceinfo_register(struct btd_service *service,
-                                               struct gatt_primary *prim)
+static void deviceinfo_driver_remove(struct btd_service *service)
 {
-       struct btd_device *device = btd_service_get_device(service);
-       struct deviceinfo *d;
-
-       d = g_new0(struct deviceinfo, 1);
-       d->dev = btd_device_ref(device);
-       d->svc_range = g_new0(struct att_range, 1);
-       d->svc_range->start = prim->range.start;
-       d->svc_range->end = prim->range.end;
-
-       btd_service_set_user_data(service, d);
-
-       d->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
-                                               attio_disconnected_cb, d);
-       return 0;
 }
 
-static int deviceinfo_driver_probe(struct btd_service *service)
+
+static int deviceinfo_driver_accept(struct btd_service *service)
 {
        struct btd_device *device = btd_service_get_device(service);
-       struct gatt_primary *prim;
+       struct gatt_db *db = btd_device_get_gatt_db(device);
+       char addr[18];
+       bt_uuid_t deviceinfo_uuid;
 
-       prim = btd_device_get_primary(device, DEVICE_INFORMATION_UUID);
-       if (prim == NULL)
-               return -EINVAL;
+       ba2str(device_get_address(device), addr);
+       DBG("deviceinfo profile accept (%s)", addr);
 
-       return deviceinfo_register(service, prim);
+       /* Handle the device info service */
+       bt_string_to_uuid(&deviceinfo_uuid, DEVICE_INFORMATION_UUID);
+       gatt_db_foreach_service(db, &deviceinfo_uuid,
+                                       foreach_deviceinfo_service, device);
+
+       return 0;
 }
 
 static struct btd_profile deviceinfo_profile = {
        .name           = "deviceinfo",
        .remote_uuid    = DEVICE_INFORMATION_UUID,
+       .external       = true,
        .device_probe   = deviceinfo_driver_probe,
-       .device_remove  = deviceinfo_driver_remove
+       .device_remove  = deviceinfo_driver_remove,
+       .accept         = deviceinfo_driver_accept,
 };
 
 static int deviceinfo_init(void)