cd2c4819acc7dc05456d4189a5355680268e7e8b
[framework/connectivity/bluez.git] / plugins / gatt-example.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2010  Nokia Corporation
6  *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <glib.h>
30 #include <bluetooth/uuid.h>
31 #include <errno.h>
32 #include <adapter.h>
33
34 #include "plugin.h"
35 #include "hcid.h"
36 #include "log.h"
37 #include "gattrib.h"
38 #include "gatt-service.h"
39 #include "att.h"
40 #include "gatt.h"
41 #include "att-database.h"
42 #include "attrib-server.h"
43
44 /* FIXME: Not defined by SIG? UUID128? */
45 #define OPCODES_SUPPORTED_UUID          0xA001
46 #define BATTERY_STATE_SVC_UUID          0xA002
47 #define BATTERY_STATE_UUID              0xA003
48 #define THERM_HUMIDITY_SVC_UUID         0xA004
49 #define MANUFACTURER_SVC_UUID           0xA005
50 #define TEMPERATURE_UUID                0xA006
51 #define FMT_CELSIUS_UUID                0xA007
52 #define FMT_OUTSIDE_UUID                0xA008
53 #define RELATIVE_HUMIDITY_UUID          0xA009
54 #define FMT_PERCENT_UUID                0xA00A
55 #define BLUETOOTH_SIG_UUID              0xA00B
56 #define MANUFACTURER_NAME_UUID          0xA00C
57 #define MANUFACTURER_SERIAL_UUID        0xA00D
58 #define VENDOR_SPECIFIC_SVC_UUID        0xA00E
59 #define VENDOR_SPECIFIC_TYPE_UUID       0xA00F
60 #define FMT_KILOGRAM_UUID               0xA010
61 #define FMT_HANGING_UUID                0xA011
62
63 struct gatt_example_adapter {
64         struct btd_adapter      *adapter;
65         GSList                  *sdp_handles;
66 };
67
68 static GSList *adapters = NULL;
69
70 static void gatt_example_adapter_free(struct gatt_example_adapter *gadapter)
71 {
72         while (gadapter->sdp_handles != NULL) {
73                 uint32_t handle = GPOINTER_TO_UINT(gadapter->sdp_handles->data);
74
75                 attrib_free_sdp(handle);
76                 gadapter->sdp_handles = g_slist_remove(gadapter->sdp_handles,
77                                                 gadapter->sdp_handles->data);
78         }
79
80         if (gadapter->adapter != NULL)
81                 btd_adapter_unref(gadapter->adapter);
82
83         g_free(gadapter);
84 }
85
86 static gint adapter_cmp(gconstpointer a, gconstpointer b)
87 {
88         const struct gatt_example_adapter *gatt_adapter = a;
89         const struct btd_adapter *adapter = b;
90
91         if (gatt_adapter->adapter == adapter)
92                 return 0;
93
94         return -1;
95 }
96
97 static uint8_t battery_state_read(struct attribute *a,
98                                   struct btd_device *device, gpointer user_data)
99 {
100         struct btd_adapter *adapter = user_data;
101         uint8_t value;
102
103         value = 0x04;
104         attrib_db_update(adapter, a->handle, NULL, &value, sizeof(value), NULL);
105
106         return 0;
107 }
108
109 static gboolean register_battery_service(struct btd_adapter *adapter)
110 {
111         bt_uuid_t uuid;
112
113         bt_uuid16_create(&uuid, BATTERY_STATE_SVC_UUID);
114
115         return gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
116                         /* battery state characteristic */
117                         GATT_OPT_CHR_UUID, BATTERY_STATE_UUID,
118                         GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
119                                                         ATT_CHAR_PROPER_NOTIFY,
120                         GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
121                                                 battery_state_read, adapter,
122
123                         GATT_OPT_INVALID);
124 }
125
126 static void register_termometer_service(struct gatt_example_adapter *adapter,
127                         const uint16_t manuf1[2], const uint16_t manuf2[2])
128 {
129         const char *desc_out_temp = "Outside Temperature";
130         const char *desc_out_hum = "Outside Relative Humidity";
131         uint16_t start_handle, h;
132         const int svc_size = 11;
133         uint32_t sdp_handle;
134         uint8_t atval[256];
135         bt_uuid_t uuid;
136         int len;
137
138         bt_uuid16_create(&uuid, THERM_HUMIDITY_SVC_UUID);
139         start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
140         if (start_handle == 0) {
141                 error("Not enough free handles to register service");
142                 return;
143         }
144
145         DBG("start_handle=0x%04x manuf1=0x%04x-0x%04x, manuf2=0x%04x-0x%04x",
146                 start_handle, manuf1[0], manuf1[1], manuf2[0], manuf2[1]);
147
148         h = start_handle;
149
150         /* Thermometer: primary service definition */
151         bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
152         att_put_u16(THERM_HUMIDITY_SVC_UUID, &atval[0]);
153         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
154                                                                 atval, 2);
155
156         bt_uuid16_create(&uuid, GATT_INCLUDE_UUID);
157
158         /* Thermometer: Include */
159         if (manuf1[0] && manuf1[1]) {
160                 att_put_u16(manuf1[0], &atval[0]);
161                 att_put_u16(manuf1[1], &atval[2]);
162                 att_put_u16(MANUFACTURER_SVC_UUID, &atval[4]);
163                 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE,
164                                                 ATT_NOT_PERMITTED, atval, 6);
165         }
166
167         /* Thermometer: Include */
168         if (manuf2[0] && manuf2[1]) {
169                 att_put_u16(manuf2[0], &atval[0]);
170                 att_put_u16(manuf2[1], &atval[2]);
171                 att_put_u16(VENDOR_SPECIFIC_SVC_UUID, &atval[4]);
172                 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE,
173                                                 ATT_NOT_PERMITTED, atval, 6);
174         }
175
176         /* Thermometer: temperature characteristic */
177         bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
178         atval[0] = ATT_CHAR_PROPER_READ;
179         att_put_u16(h + 1, &atval[1]);
180         att_put_u16(TEMPERATURE_UUID, &atval[3]);
181         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
182                                                                 atval, 5);
183
184         /* Thermometer: temperature characteristic value */
185         bt_uuid16_create(&uuid, TEMPERATURE_UUID);
186         atval[0] = 0x8A;
187         atval[1] = 0x02;
188         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
189                                                                 atval, 2);
190
191         /* Thermometer: temperature characteristic format */
192         bt_uuid16_create(&uuid, GATT_CHARAC_FMT_UUID);
193         atval[0] = 0x0E;
194         atval[1] = 0xFE;
195         att_put_u16(FMT_CELSIUS_UUID, &atval[2]);
196         atval[4] = 0x01;
197         att_put_u16(FMT_OUTSIDE_UUID, &atval[5]);
198         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
199                                                                 atval, 7);
200
201         /* Thermometer: characteristic user description */
202         bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
203         len = strlen(desc_out_temp);
204         strncpy((char *) atval, desc_out_temp, len);
205         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
206                                                                 atval, len);
207
208         /* Thermometer: relative humidity characteristic */
209         bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
210         atval[0] = ATT_CHAR_PROPER_READ;
211         att_put_u16(h + 1, &atval[1]);
212         att_put_u16(RELATIVE_HUMIDITY_UUID, &atval[3]);
213         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
214                                                                 atval, 5);
215
216         /* Thermometer: relative humidity value */
217         bt_uuid16_create(&uuid, RELATIVE_HUMIDITY_UUID);
218         atval[0] = 0x27;
219         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
220                                                                 atval, 1);
221
222         /* Thermometer: relative humidity characteristic format */
223         bt_uuid16_create(&uuid, GATT_CHARAC_FMT_UUID);
224         atval[0] = 0x04;
225         atval[1] = 0x00;
226         att_put_u16(FMT_PERCENT_UUID, &atval[2]);
227         att_put_u16(BLUETOOTH_SIG_UUID, &atval[4]);
228         att_put_u16(FMT_OUTSIDE_UUID, &atval[6]);
229         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
230                                                                 atval, 8);
231
232         /* Thermometer: characteristic user description */
233         bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
234         len = strlen(desc_out_hum);
235         strncpy((char *) atval, desc_out_hum, len);
236         attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
237                                                                 atval, len);
238
239         g_assert(h - start_handle + 1 == svc_size);
240
241         /* Add an SDP record for the above service */
242         sdp_handle = attrib_create_sdp(adapter->adapter, start_handle,
243                                                                 "Thermometer");
244         if (sdp_handle)
245                 adapter->sdp_handles = g_slist_prepend(adapter->sdp_handles,
246                                                 GUINT_TO_POINTER(sdp_handle));
247 }
248
249 static void register_manuf1_service(struct gatt_example_adapter *adapter,
250                                                         uint16_t range[2])
251 {
252         const char *manufacturer_name1 = "ACME Temperature Sensor";
253         const char *serial1 = "237495-3282-A";
254         uint16_t start_handle, h;
255         const int svc_size = 5;
256         uint8_t atval[256];
257         bt_uuid_t uuid;
258         int len;
259
260         bt_uuid16_create(&uuid, MANUFACTURER_SVC_UUID);
261         start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
262         if (start_handle == 0) {
263                 error("Not enough free handles to register service");
264                 return;
265         }
266
267         DBG("start_handle=0x%04x", start_handle);
268
269         h = start_handle;
270
271         /* Secondary Service: Manufacturer Service */
272         bt_uuid16_create(&uuid, GATT_SND_SVC_UUID);
273         att_put_u16(MANUFACTURER_SVC_UUID, &atval[0]);
274         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
275                                                                 atval, 2);
276
277         /* Manufacturer name characteristic definition */
278         bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
279         atval[0] = ATT_CHAR_PROPER_READ;
280         att_put_u16(h + 1, &atval[1]);
281         att_put_u16(MANUFACTURER_NAME_UUID, &atval[3]);
282         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
283                                                                 atval, 5);
284
285         /* Manufacturer name characteristic value */
286         bt_uuid16_create(&uuid, MANUFACTURER_NAME_UUID);
287         len = strlen(manufacturer_name1);
288         strncpy((char *) atval, manufacturer_name1, len);
289         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
290                                                                 atval, len);
291
292         /* Manufacturer serial number characteristic */
293         bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
294         atval[0] = ATT_CHAR_PROPER_READ;
295         att_put_u16(h + 1, &atval[1]);
296         att_put_u16(MANUFACTURER_SERIAL_UUID, &atval[3]);
297         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
298                                                                 atval, 5);
299
300         /* Manufacturer serial number characteristic value */
301         bt_uuid16_create(&uuid, MANUFACTURER_SERIAL_UUID);
302         len = strlen(serial1);
303         strncpy((char *) atval, serial1, len);
304         attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
305                                                                 atval, len);
306
307         g_assert(h - start_handle + 1 == svc_size);
308
309         range[0] = start_handle;
310         range[1] = start_handle + svc_size - 1;
311 }
312
313 static void register_manuf2_service(struct gatt_example_adapter *adapter,
314                                                         uint16_t range[2])
315 {
316         const char *manufacturer_name2 = "ACME Weighing Scales";
317         const char *serial2 = "11267-2327A00239";
318         uint16_t start_handle, h;
319         const int svc_size = 5;
320         uint8_t atval[256];
321         bt_uuid_t uuid;
322         int len;
323
324         bt_uuid16_create(&uuid, MANUFACTURER_SVC_UUID);
325         start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
326         if (start_handle == 0) {
327                 error("Not enough free handles to register service");
328                 return;
329         }
330
331         DBG("start_handle=0x%04x", start_handle);
332
333         h = start_handle;
334
335         /* Secondary Service: Manufacturer Service */
336         bt_uuid16_create(&uuid, GATT_SND_SVC_UUID);
337         att_put_u16(MANUFACTURER_SVC_UUID, &atval[0]);
338         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
339                                                                 atval, 2);
340
341         /* Manufacturer name characteristic definition */
342         bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
343         atval[0] = ATT_CHAR_PROPER_READ;
344         att_put_u16(h + 1, &atval[1]);
345         att_put_u16(MANUFACTURER_NAME_UUID, &atval[3]);
346         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
347                                                                 atval, 5);
348
349         /* Manufacturer name attribute */
350         bt_uuid16_create(&uuid, MANUFACTURER_NAME_UUID);
351         len = strlen(manufacturer_name2);
352         strncpy((char *) atval, manufacturer_name2, len);
353         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
354                                                                 atval, len);
355
356         /* Characteristic: serial number */
357         bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
358         atval[0] = ATT_CHAR_PROPER_READ;
359         att_put_u16(h + 1, &atval[1]);
360         att_put_u16(MANUFACTURER_SERIAL_UUID, &atval[3]);
361         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
362                                                                 atval, 5);
363
364         /* Serial number characteristic value */
365         bt_uuid16_create(&uuid, MANUFACTURER_SERIAL_UUID);
366         len = strlen(serial2);
367         strncpy((char *) atval, serial2, len);
368         attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
369                                                                 atval, len);
370
371         g_assert(h - start_handle + 1 == svc_size);
372
373         range[0] = start_handle;
374         range[1] = start_handle + svc_size - 1;
375 }
376
377 static void register_vendor_service(struct gatt_example_adapter *adapter,
378                                                         uint16_t range[2])
379 {
380         uint16_t start_handle, h;
381         const int svc_size = 3;
382         uint8_t atval[256];
383         bt_uuid_t uuid;
384
385         bt_uuid16_create(&uuid, VENDOR_SPECIFIC_SVC_UUID);
386         start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
387         if (start_handle == 0) {
388                 error("Not enough free handles to register service");
389                 return;
390         }
391
392         DBG("start_handle=0x%04x", start_handle);
393
394         h = start_handle;
395
396         /* Secondary Service: Vendor Specific Service */
397         bt_uuid16_create(&uuid, GATT_SND_SVC_UUID);
398         att_put_u16(VENDOR_SPECIFIC_SVC_UUID, &atval[0]);
399         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
400                                                                 atval, 2);
401
402         /* Vendor Specific Type characteristic definition */
403         bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
404         atval[0] = ATT_CHAR_PROPER_READ;
405         att_put_u16(h + 1, &atval[1]);
406         att_put_u16(VENDOR_SPECIFIC_TYPE_UUID, &atval[3]);
407         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
408                                                                 atval, 5);
409
410         /* Vendor Specific Type characteristic value */
411         bt_uuid16_create(&uuid, VENDOR_SPECIFIC_TYPE_UUID);
412         atval[0] = 0x56;
413         atval[1] = 0x65;
414         atval[2] = 0x6E;
415         atval[3] = 0x64;
416         atval[4] = 0x6F;
417         atval[5] = 0x72;
418         attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
419                                                                 atval, 6);
420
421         g_assert(h - start_handle + 1 == svc_size);
422
423         range[0] = start_handle;
424         range[1] = start_handle + svc_size - 1;
425 }
426
427 static void register_weight_service(struct gatt_example_adapter *adapter,
428                                                 const uint16_t vendor[2])
429 {
430         const char *desc_weight = "Rucksack Weight";
431         const uint128_t char_weight_uuid_btorder = {
432                 .data = { 0x80, 0x88, 0xF2, 0x18, 0x90, 0x2C, 0x45, 0x0B,
433                           0xB6, 0xC4, 0x62, 0x89, 0x1E, 0x8C, 0x25, 0xE9 } };
434         const uint128_t prim_weight_uuid_btorder = {
435                 .data = { 0x4F, 0x0A, 0xC0, 0x96, 0x35, 0xD4, 0x49, 0x11,
436                           0x96, 0x31, 0xDE, 0xA8, 0xDC, 0x74, 0xEE, 0xFE } };
437         uint128_t prim_weight_uuid, char_weight_uuid;
438         uint16_t start_handle, h;
439         const int svc_size = 6;
440         uint32_t sdp_handle;
441         uint8_t atval[256];
442         bt_uuid_t uuid;
443         int len;
444
445         btoh128(&char_weight_uuid_btorder, &char_weight_uuid);
446         btoh128(&prim_weight_uuid_btorder, &prim_weight_uuid);
447         bt_uuid128_create(&uuid, prim_weight_uuid);
448         start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
449         if (start_handle == 0) {
450                 error("Not enough free handles to register service");
451                 return;
452         }
453
454         DBG("start_handle=0x%04x, vendor=0x%04x-0x%04x", start_handle,
455                                                         vendor[0], vendor[1]);
456
457         h = start_handle;
458
459         /* Weight service: primary service definition */
460         bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
461         memcpy(atval, &prim_weight_uuid_btorder, 16);
462         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
463                                                                 atval, 16);
464
465         if (vendor[0] && vendor[1]) {
466                 /* Weight: include */
467                 bt_uuid16_create(&uuid, GATT_INCLUDE_UUID);
468                 att_put_u16(vendor[0], &atval[0]);
469                 att_put_u16(vendor[1], &atval[2]);
470                 att_put_u16(MANUFACTURER_SVC_UUID, &atval[4]);
471                 attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE,
472                                                 ATT_NOT_PERMITTED, atval, 6);
473         }
474
475         /* Weight: characteristic */
476         bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
477         atval[0] = ATT_CHAR_PROPER_READ;
478         att_put_u16(h + 1, &atval[1]);
479         memcpy(&atval[3], &char_weight_uuid_btorder, 16);
480         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
481                                                                 atval, 19);
482
483         /* Weight: characteristic value */
484         bt_uuid128_create(&uuid, char_weight_uuid);
485         atval[0] = 0x82;
486         atval[1] = 0x55;
487         atval[2] = 0x00;
488         atval[3] = 0x00;
489         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
490                                                                 atval, 4);
491
492         /* Weight: characteristic format */
493         bt_uuid16_create(&uuid, GATT_CHARAC_FMT_UUID);
494         atval[0] = 0x08;
495         atval[1] = 0xFD;
496         att_put_u16(FMT_KILOGRAM_UUID, &atval[2]);
497         att_put_u16(BLUETOOTH_SIG_UUID, &atval[4]);
498         att_put_u16(FMT_HANGING_UUID, &atval[6]);
499         attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
500                                                                 atval, 8);
501
502         /* Weight: characteristic user description */
503         bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
504         len = strlen(desc_weight);
505         strncpy((char *) atval, desc_weight, len);
506         attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
507                                                                 atval, len);
508         g_assert(h - start_handle + 1 == svc_size);
509
510         /* Add an SDP record for the above service */
511         sdp_handle = attrib_create_sdp(adapter->adapter, start_handle,
512                                                         "Weight Service");
513         if (sdp_handle)
514                 adapter->sdp_handles = g_slist_prepend(adapter->sdp_handles,
515                                                 GUINT_TO_POINTER(sdp_handle));
516 }
517
518 static int gatt_example_adapter_probe(struct btd_adapter *adapter)
519 {
520         uint16_t manuf1_range[2] = {0, 0}, manuf2_range[2] = {0, 0};
521         uint16_t vendor_range[2] = {0, 0};
522         struct gatt_example_adapter *gadapter;
523
524         gadapter = g_new0(struct gatt_example_adapter, 1);
525         gadapter->adapter = btd_adapter_ref(adapter);
526
527         if (!register_battery_service(adapter)) {
528                 DBG("Battery service could not be registered");
529                 gatt_example_adapter_free(gadapter);
530                 return -EIO;
531         }
532
533         register_manuf1_service(gadapter, manuf1_range);
534         register_manuf2_service(gadapter, manuf2_range);
535         register_termometer_service(gadapter, manuf1_range, manuf2_range);
536         register_vendor_service(gadapter, vendor_range);
537         register_weight_service(gadapter, vendor_range);
538
539         adapters = g_slist_append(adapters, gadapter);
540
541         return 0;
542 }
543
544 static void gatt_example_adapter_remove(struct btd_adapter *adapter)
545 {
546         struct gatt_example_adapter *gadapter;
547         GSList *l;
548
549         l = g_slist_find_custom(adapters, adapter, adapter_cmp);
550         if (l == NULL)
551                 return;
552
553         gadapter = l->data;
554         adapters = g_slist_remove(adapters, gadapter);
555         gatt_example_adapter_free(gadapter);
556 }
557
558 static struct btd_adapter_driver gatt_example_adapter_driver = {
559         .name   = "gatt-example-adapter-driver",
560         .probe  = gatt_example_adapter_probe,
561         .remove = gatt_example_adapter_remove,
562 };
563
564 static int gatt_example_init(void)
565 {
566         if (!main_opts.gatt_enabled) {
567                 DBG("GATT is disabled");
568                 return -ENOTSUP;
569         }
570
571         return btd_register_adapter_driver(&gatt_example_adapter_driver);
572 }
573
574 static void gatt_example_exit(void)
575 {
576         if (!main_opts.gatt_enabled)
577                 return;
578
579         btd_unregister_adapter_driver(&gatt_example_adapter_driver);
580 }
581
582 BLUETOOTH_PLUGIN_DEFINE(gatt_example, VERSION, BLUETOOTH_PLUGIN_PRIORITY_LOW,
583                                         gatt_example_init, gatt_example_exit)