1 /* Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6 #include <dbus/dbus.h>
7
8 #include <errno.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <syslog.h>
13 #include <sys/socket.h>
14 #include <sys/ioctl.h>
15
16 #include "bluetooth.h"
17 #include "cras_bt_adapter.h"
18 #include "cras_bt_constants.h"
19 #include "utlist.h"
20
21 struct cras_bt_adapter {
22 char *object_path;
23 char *address;
24 char *name;
25 uint32_t bluetooth_class;
26 int powered;
27 int bus_type;
28
29 struct cras_bt_adapter *prev, *next;
30 };
31
32 static struct cras_bt_adapter *adapters;
33
cras_bt_adapter_query_bus_type(struct cras_bt_adapter * adapter)34 static int cras_bt_adapter_query_bus_type(struct cras_bt_adapter *adapter)
35 {
36 static const char *hci_str = "hci";
37 struct hci_dev_info dev_info;
38 char *pos;
39 int ctl, err;
40
41 /* Object path [variable prefix]/{hci0,hci1,...} */
42 pos = strstr(adapter->object_path, hci_str);
43 if (!pos)
44 return -1;
45
46 ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
47 if (ctl < 0) {
48 syslog(LOG_ERR, "Error creating HCI ctl socket");
49 return -1;
50 }
51
52 /* dev_id = 0 for hci0 */
53 dev_info.type = 0;
54 dev_info.dev_id = atoi(pos + 3);
55 err = ioctl(ctl, HCIGETDEVINFO, (void *)&dev_info);
56 if (err) {
57 syslog(LOG_ERR, "HCI get dev info error %s", strerror(errno));
58 close(ctl);
59 return -1;
60 }
61 if ((dev_info.type & 0x0f) < HCI_BUS_MAX)
62 adapter->bus_type = (dev_info.type & 0x0f);
63
64 close(ctl);
65 return 0;
66 }
67
cras_bt_adapter_create(const char * object_path)68 struct cras_bt_adapter *cras_bt_adapter_create(const char *object_path)
69 {
70 struct cras_bt_adapter *adapter;
71
72 adapter = calloc(1, sizeof(*adapter));
73 if (adapter == NULL)
74 return NULL;
75
76 adapter->object_path = strdup(object_path);
77 if (adapter->object_path == NULL) {
78 free(adapter);
79 return NULL;
80 }
81
82 DL_APPEND(adapters, adapter);
83
84 /* Set bus type to USB as default when query fails. */
85 if (cras_bt_adapter_query_bus_type(adapter))
86 adapter->bus_type = HCI_USB;
87
88 return adapter;
89 }
90
cras_bt_adapter_destroy(struct cras_bt_adapter * adapter)91 void cras_bt_adapter_destroy(struct cras_bt_adapter *adapter)
92 {
93 DL_DELETE(adapters, adapter);
94
95 free(adapter->object_path);
96 free(adapter->address);
97 free(adapter->name);
98 free(adapter);
99 }
100
cras_bt_adapter_reset()101 void cras_bt_adapter_reset()
102 {
103 while (adapters) {
104 syslog(LOG_INFO, "Bluetooth Adapter: %s removed",
105 adapters->address);
106 cras_bt_adapter_destroy(adapters);
107 }
108 }
109
110
cras_bt_adapter_get(const char * object_path)111 struct cras_bt_adapter *cras_bt_adapter_get(const char *object_path)
112 {
113 struct cras_bt_adapter *adapter;
114
115 if (object_path == NULL)
116 return NULL;
117
118 DL_FOREACH(adapters, adapter) {
119 if (strcmp(adapter->object_path, object_path) == 0)
120 return adapter;
121 }
122
123 return NULL;
124 }
125
cras_bt_adapter_get_list(struct cras_bt_adapter *** adapter_list_out)126 size_t cras_bt_adapter_get_list(struct cras_bt_adapter ***adapter_list_out)
127 {
128 struct cras_bt_adapter *adapter;
129 struct cras_bt_adapter **adapter_list = NULL;
130 size_t num_adapters = 0;
131
132 DL_FOREACH(adapters, adapter) {
133 struct cras_bt_adapter **tmp;
134
135 tmp = realloc(adapter_list,
136 sizeof(adapter_list[0]) * (num_adapters + 1));
137 if (!tmp) {
138 free(adapter_list);
139 return -ENOMEM;
140 }
141
142 adapter_list = tmp;
143 adapter_list[num_adapters++] = adapter;
144 }
145
146 *adapter_list_out = adapter_list;
147 return num_adapters;
148 }
149
cras_bt_adapter_object_path(const struct cras_bt_adapter * adapter)150 const char *cras_bt_adapter_object_path(const struct cras_bt_adapter *adapter)
151 {
152 return adapter->object_path;
153 }
154
cras_bt_adapter_address(const struct cras_bt_adapter * adapter)155 const char *cras_bt_adapter_address(const struct cras_bt_adapter *adapter)
156 {
157 return adapter->address;
158 }
159
cras_bt_adapter_name(const struct cras_bt_adapter * adapter)160 const char *cras_bt_adapter_name(const struct cras_bt_adapter *adapter)
161 {
162 return adapter->name;
163 }
164
cras_bt_adapter_powered(const struct cras_bt_adapter * adapter)165 int cras_bt_adapter_powered(const struct cras_bt_adapter *adapter)
166 {
167 return adapter->powered;
168 }
169
170
cras_bt_adapter_update_properties(struct cras_bt_adapter * adapter,DBusMessageIter * properties_array_iter,DBusMessageIter * invalidated_array_iter)171 void cras_bt_adapter_update_properties(struct cras_bt_adapter *adapter,
172 DBusMessageIter *properties_array_iter,
173 DBusMessageIter *invalidated_array_iter)
174 {
175 while (dbus_message_iter_get_arg_type(properties_array_iter) !=
176 DBUS_TYPE_INVALID) {
177 DBusMessageIter properties_dict_iter, variant_iter;
178 const char *key;
179 int type;
180
181 dbus_message_iter_recurse(properties_array_iter,
182 &properties_dict_iter);
183
184 dbus_message_iter_get_basic(&properties_dict_iter, &key);
185 dbus_message_iter_next(&properties_dict_iter);
186
187 dbus_message_iter_recurse(&properties_dict_iter, &variant_iter);
188 type = dbus_message_iter_get_arg_type(&variant_iter);
189
190 if (type == DBUS_TYPE_STRING) {
191 const char *value;
192
193 dbus_message_iter_get_basic(&variant_iter, &value);
194
195 if (strcmp(key, "Address") == 0) {
196 free(adapter->address);
197 adapter->address = strdup(value);
198
199 } else if (strcmp(key, "Alias") == 0) {
200 free(adapter->name);
201 adapter->name = strdup(value);
202
203 }
204
205 } else if (type == DBUS_TYPE_UINT32) {
206 uint32_t value;
207
208 dbus_message_iter_get_basic(&variant_iter, &value);
209
210 if (strcmp(key, "Class") == 0)
211 adapter->bluetooth_class = value;
212
213 } else if (type == DBUS_TYPE_BOOLEAN) {
214 int value;
215
216 dbus_message_iter_get_basic(&variant_iter, &value);
217
218 if (strcmp(key, "Powered") == 0)
219 adapter->powered = value;
220
221 }
222
223 dbus_message_iter_next(properties_array_iter);
224 }
225
226 while (invalidated_array_iter &&
227 dbus_message_iter_get_arg_type(invalidated_array_iter) !=
228 DBUS_TYPE_INVALID) {
229 const char *key;
230
231 dbus_message_iter_get_basic(invalidated_array_iter, &key);
232
233 if (strcmp(key, "Address") == 0) {
234 free(adapter->address);
235 adapter->address = NULL;
236 } else if (strcmp(key, "Alias") == 0) {
237 free(adapter->name);
238 adapter->name = NULL;
239 } else if (strcmp(key, "Class") == 0) {
240 adapter->bluetooth_class = 0;
241 } else if (strcmp(key, "Powered") == 0) {
242 adapter->powered = 0;
243 }
244
245 dbus_message_iter_next(invalidated_array_iter);
246 }
247 }
248
cras_bt_adapter_on_usb(struct cras_bt_adapter * adapter)249 int cras_bt_adapter_on_usb(struct cras_bt_adapter *adapter)
250 {
251 return !!(adapter->bus_type == HCI_USB);
252 }