Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / android / dis.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2012 Texas Instruments, Inc.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdbool.h>
28 #include <errno.h>
29
30 #include <glib.h>
31
32 #include "src/log.h"
33
34 #include "lib/bluetooth.h"
35 #include "lib/sdp.h"
36 #include "lib/uuid.h"
37
38 #include "src/shared/util.h"
39 #include "src/shared/queue.h"
40
41 #include "attrib/gattrib.h"
42 #include "attrib/att.h"
43 #include "attrib/gatt.h"
44
45 #include "android/dis.h"
46
47 #define PNP_ID_SIZE     7
48
49 struct bt_dis {
50         int                     ref_count;
51         uint16_t                handle;
52         uint8_t                 source;
53         uint16_t                vendor;
54         uint16_t                product;
55         uint16_t                version;
56         GAttrib                 *attrib;        /* GATT connection */
57         struct gatt_primary     *primary;       /* Primary details */
58         bt_dis_notify           notify;
59         void                    *notify_data;
60         struct queue            *gatt_op;
61 };
62
63 struct characteristic {
64         struct gatt_char        attr;   /* Characteristic */
65         struct bt_dis           *d;     /* deviceinfo where the char belongs */
66 };
67
68 struct gatt_request {
69         unsigned int id;
70         struct bt_dis *dis;
71         void *user_data;
72 };
73
74 static void destroy_gatt_req(struct gatt_request *req)
75 {
76         queue_remove(req->dis->gatt_op, req);
77         bt_dis_unref(req->dis);
78         free(req);
79 }
80
81 static void dis_free(struct bt_dis *dis)
82 {
83         bt_dis_detach(dis);
84
85         g_free(dis->primary);
86         queue_destroy(dis->gatt_op, (void *) destroy_gatt_req);
87         g_free(dis);
88 }
89
90 struct bt_dis *bt_dis_new(void *primary)
91 {
92         struct bt_dis *dis;
93
94         dis = g_try_new0(struct bt_dis, 1);
95         if (!dis)
96                 return NULL;
97
98         dis->gatt_op = queue_new();
99         if (!dis->gatt_op) {
100                 dis_free(dis);
101                 return NULL;
102         }
103
104         if (primary)
105                 dis->primary = g_memdup(primary, sizeof(*dis->primary));
106
107         return bt_dis_ref(dis);
108 }
109
110 struct bt_dis *bt_dis_ref(struct bt_dis *dis)
111 {
112         if (!dis)
113                 return NULL;
114
115         __sync_fetch_and_add(&dis->ref_count, 1);
116
117         return dis;
118 }
119
120 void bt_dis_unref(struct bt_dis *dis)
121 {
122         if (!dis)
123                 return;
124
125         if (__sync_sub_and_fetch(&dis->ref_count, 1))
126                 return;
127
128         dis_free(dis);
129 }
130
131 static struct gatt_request *create_request(struct bt_dis *dis,
132                                                         void *user_data)
133 {
134         struct gatt_request *req;
135
136         req = new0(struct gatt_request, 1);
137         if (!req)
138                 return NULL;
139
140         req->user_data = user_data;
141         req->dis = bt_dis_ref(dis);
142
143         return req;
144 }
145
146 static bool set_and_store_gatt_req(struct bt_dis *dis,
147                                                 struct gatt_request *req,
148                                                 unsigned int id)
149 {
150         req->id = id;
151         return queue_push_head(dis->gatt_op, req);
152 }
153
154 static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
155                                                         gpointer user_data)
156 {
157         struct gatt_request *req = user_data;
158         struct bt_dis *dis = req->user_data;
159         uint8_t value[PNP_ID_SIZE];
160         ssize_t vlen;
161
162         destroy_gatt_req(req);
163
164         if (status != 0) {
165                 error("Error reading PNP_ID value: %s", att_ecode2str(status));
166                 return;
167         }
168
169         vlen = dec_read_resp(pdu, len, value, sizeof(value));
170         if (vlen < 0) {
171                 error("Error reading PNP_ID: Protocol error");
172                 return;
173         }
174
175         if (vlen < 7) {
176                 error("Error reading PNP_ID: Invalid pdu length received");
177                 return;
178         }
179
180         dis->source = value[0];
181         dis->vendor = get_le16(&value[1]);
182         dis->product = get_le16(&value[3]);
183         dis->version = get_le16(&value[5]);
184
185         DBG("source: 0x%02X vendor: 0x%04X product: 0x%04X version: 0x%04X",
186                         dis->source, dis->vendor, dis->product, dis->version);
187
188         if (dis->notify)
189                 dis->notify(dis->source, dis->vendor, dis->product,
190                                                 dis->version, dis->notify_data);
191 }
192
193 static void read_char(struct bt_dis *dis, GAttrib *attrib, uint16_t handle,
194                                 GAttribResultFunc func, gpointer user_data)
195 {
196         struct gatt_request *req;
197         unsigned int id;
198
199         req = create_request(dis, user_data);
200         if (!req)
201                 return;
202
203         id = gatt_read_char(attrib, handle, func, req);
204
205         if (set_and_store_gatt_req(dis, req, id))
206                 return;
207
208         error("dis: Could not read characteristic");
209         g_attrib_cancel(attrib, id);
210         free(req);
211 }
212
213 static void discover_char(struct bt_dis *dis, GAttrib *attrib,
214                                                 uint16_t start, uint16_t end,
215                                                 bt_uuid_t *uuid, gatt_cb_t func,
216                                                 gpointer user_data)
217 {
218         struct gatt_request *req;
219         unsigned int id;
220
221         req = create_request(dis, user_data);
222         if (!req)
223                 return;
224
225         id = gatt_discover_char(attrib, start, end, uuid, func, req);
226
227         if (set_and_store_gatt_req(dis, req, id))
228                 return;
229
230         error("dis: Could not send discover characteristic");
231         g_attrib_cancel(attrib, id);
232         free(req);
233 }
234
235 static void configure_deviceinfo_cb(uint8_t status, GSList *characteristics,
236                                                                 void *user_data)
237 {
238         struct gatt_request *req = user_data;
239         struct bt_dis *d = req->user_data;
240         GSList *l;
241
242         destroy_gatt_req(req);
243
244         if (status != 0) {
245                 error("Discover deviceinfo characteristics: %s",
246                                                         att_ecode2str(status));
247                 return;
248         }
249
250         for (l = characteristics; l; l = l->next) {
251                 struct gatt_char *c = l->data;
252
253                 if (strcmp(c->uuid, PNPID_UUID) == 0) {
254                         d->handle = c->value_handle;
255                         read_char(d, d->attrib, d->handle, read_pnpid_cb, d);
256                         break;
257                 }
258         }
259 }
260
261 bool bt_dis_attach(struct bt_dis *dis, void *attrib)
262 {
263         struct gatt_primary *primary = dis->primary;
264
265         if (dis->attrib || !primary)
266                 return false;
267
268         dis->attrib = g_attrib_ref(attrib);
269
270         if (!dis->handle)
271                 discover_char(dis, dis->attrib, primary->range.start,
272                                                 primary->range.end, NULL,
273                                                 configure_deviceinfo_cb, dis);
274
275         return true;
276 }
277
278 static void cancel_gatt_req(struct gatt_request *req)
279 {
280         if (g_attrib_cancel(req->dis->attrib, req->id))
281                 destroy_gatt_req(req);
282 }
283
284 void bt_dis_detach(struct bt_dis *dis)
285 {
286         if (!dis->attrib)
287                 return;
288
289         queue_foreach(dis->gatt_op, (void *) cancel_gatt_req, NULL);
290         g_attrib_unref(dis->attrib);
291         dis->attrib = NULL;
292 }
293
294 bool bt_dis_set_notification(struct bt_dis *dis, bt_dis_notify func,
295                                                         void *user_data)
296 {
297         if (!dis)
298                 return false;
299
300         dis->notify = func;
301         dis->notify_data = user_data;
302
303         return true;
304 }