• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2013 The Chromium OS 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 /*
22  * Object to represent a bluetooth adapter on the system. Used to query the
23  * capabilities regarding certain bluetooth audio.
24  * Members:
25  *    conn - The dbus connection used to send message to bluetoothd.
26  *    object_path - Object path of the bluetooth adapter.
27  *    address - The BT address of this adapter.
28  *    name - The readable name of this adapter.
29  *    bluetooth_class - The bluetooth class of device.
30  *    powered - Powered on or off.
31  *    bus_type - Type of bus this adapter runs on.
32  *    wide_band_speech - If this adapter supports wide band speech.
33  */
34 struct cras_bt_adapter {
35 	DBusConnection *conn;
36 	char *object_path;
37 	char *address;
38 	char *name;
39 	uint32_t bluetooth_class;
40 	int powered;
41 	int bus_type;
42 	int wide_band_speech;
43 
44 	struct cras_bt_adapter *prev, *next;
45 };
46 
47 static struct cras_bt_adapter *adapters;
48 
cras_bt_adapter_query_bus_type(struct cras_bt_adapter * adapter)49 static int cras_bt_adapter_query_bus_type(struct cras_bt_adapter *adapter)
50 {
51 	static const char *hci_str = "hci";
52 	struct hci_dev_info dev_info;
53 	char *pos;
54 	int ctl, err;
55 
56 	/* Object path [variable prefix]/{hci0,hci1,...} */
57 	pos = strstr(adapter->object_path, hci_str);
58 	if (!pos)
59 		return -1;
60 
61 	ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
62 	if (ctl < 0) {
63 		syslog(LOG_ERR, "Error creating HCI ctl socket");
64 		return -1;
65 	}
66 
67 	/* dev_id = 0 for hci0 */
68 	dev_info.type = 0;
69 	dev_info.dev_id = atoi(pos + 3);
70 	err = ioctl(ctl, HCIGETDEVINFO, (void *)&dev_info);
71 	if (err) {
72 		syslog(LOG_ERR, "HCI get dev info error %s", strerror(errno));
73 		close(ctl);
74 		return -1;
75 	}
76 	if ((dev_info.type & 0x0f) < HCI_BUS_MAX)
77 		adapter->bus_type = (dev_info.type & 0x0f);
78 
79 	close(ctl);
80 	return 0;
81 }
82 
cras_bt_adapter_create(DBusConnection * conn,const char * object_path)83 struct cras_bt_adapter *cras_bt_adapter_create(DBusConnection *conn,
84 					       const char *object_path)
85 {
86 	struct cras_bt_adapter *adapter;
87 
88 	adapter = calloc(1, sizeof(*adapter));
89 	if (adapter == NULL)
90 		return NULL;
91 
92 	adapter->conn = conn;
93 	adapter->object_path = strdup(object_path);
94 	if (adapter->object_path == NULL) {
95 		free(adapter);
96 		return NULL;
97 	}
98 
99 	DL_APPEND(adapters, adapter);
100 
101 	/* Set bus type to USB as default when query fails. */
102 	if (cras_bt_adapter_query_bus_type(adapter))
103 		adapter->bus_type = HCI_USB;
104 
105 	return adapter;
106 }
107 
cras_bt_adapter_destroy(struct cras_bt_adapter * adapter)108 void cras_bt_adapter_destroy(struct cras_bt_adapter *adapter)
109 {
110 	DL_DELETE(adapters, adapter);
111 
112 	free(adapter->object_path);
113 	free(adapter->address);
114 	free(adapter->name);
115 	free(adapter);
116 }
117 
cras_bt_adapter_reset()118 void cras_bt_adapter_reset()
119 {
120 	while (adapters) {
121 		syslog(LOG_INFO, "Bluetooth Adapter: %s removed",
122 		       adapters->address);
123 		cras_bt_adapter_destroy(adapters);
124 	}
125 }
126 
cras_bt_adapter_get(const char * object_path)127 struct cras_bt_adapter *cras_bt_adapter_get(const char *object_path)
128 {
129 	struct cras_bt_adapter *adapter;
130 
131 	if (object_path == NULL)
132 		return NULL;
133 
134 	DL_FOREACH (adapters, adapter) {
135 		if (strcmp(adapter->object_path, object_path) == 0)
136 			return adapter;
137 	}
138 
139 	return NULL;
140 }
141 
cras_bt_adapter_get_list(struct cras_bt_adapter *** adapter_list_out)142 size_t cras_bt_adapter_get_list(struct cras_bt_adapter ***adapter_list_out)
143 {
144 	struct cras_bt_adapter *adapter;
145 	struct cras_bt_adapter **adapter_list = NULL;
146 	size_t num_adapters = 0;
147 
148 	DL_FOREACH (adapters, adapter) {
149 		struct cras_bt_adapter **tmp;
150 
151 		tmp = realloc(adapter_list,
152 			      sizeof(adapter_list[0]) * (num_adapters + 1));
153 		if (!tmp) {
154 			free(adapter_list);
155 			return -ENOMEM;
156 		}
157 
158 		adapter_list = tmp;
159 		adapter_list[num_adapters++] = adapter;
160 	}
161 
162 	*adapter_list_out = adapter_list;
163 	return num_adapters;
164 }
165 
cras_bt_adapter_object_path(const struct cras_bt_adapter * adapter)166 const char *cras_bt_adapter_object_path(const struct cras_bt_adapter *adapter)
167 {
168 	return adapter->object_path;
169 }
170 
cras_bt_adapter_address(const struct cras_bt_adapter * adapter)171 const char *cras_bt_adapter_address(const struct cras_bt_adapter *adapter)
172 {
173 	return adapter->address;
174 }
175 
cras_bt_adapter_name(const struct cras_bt_adapter * adapter)176 const char *cras_bt_adapter_name(const struct cras_bt_adapter *adapter)
177 {
178 	return adapter->name;
179 }
180 
cras_bt_adapter_powered(const struct cras_bt_adapter * adapter)181 int cras_bt_adapter_powered(const struct cras_bt_adapter *adapter)
182 {
183 	return adapter->powered;
184 }
185 
cras_bt_adapter_wbs_supported(struct cras_bt_adapter * adapter)186 int cras_bt_adapter_wbs_supported(struct cras_bt_adapter *adapter)
187 {
188 	return adapter->wide_band_speech;
189 }
190 
bt_adapter_set_powered(struct cras_bt_adapter * adapter,int powered)191 static void bt_adapter_set_powered(struct cras_bt_adapter *adapter, int powered)
192 {
193 	adapter->powered = powered;
194 	if (powered)
195 		cras_bt_adapter_get_supported_capabilities(adapter);
196 }
197 
cras_bt_adapter_update_properties(struct cras_bt_adapter * adapter,DBusMessageIter * properties_array_iter,DBusMessageIter * invalidated_array_iter)198 void cras_bt_adapter_update_properties(struct cras_bt_adapter *adapter,
199 				       DBusMessageIter *properties_array_iter,
200 				       DBusMessageIter *invalidated_array_iter)
201 {
202 	while (dbus_message_iter_get_arg_type(properties_array_iter) !=
203 	       DBUS_TYPE_INVALID) {
204 		DBusMessageIter properties_dict_iter, variant_iter;
205 		const char *key;
206 		int type;
207 
208 		dbus_message_iter_recurse(properties_array_iter,
209 					  &properties_dict_iter);
210 
211 		dbus_message_iter_get_basic(&properties_dict_iter, &key);
212 		dbus_message_iter_next(&properties_dict_iter);
213 
214 		dbus_message_iter_recurse(&properties_dict_iter, &variant_iter);
215 		type = dbus_message_iter_get_arg_type(&variant_iter);
216 
217 		if (type == DBUS_TYPE_STRING) {
218 			const char *value;
219 
220 			dbus_message_iter_get_basic(&variant_iter, &value);
221 
222 			if (strcmp(key, "Address") == 0) {
223 				free(adapter->address);
224 				adapter->address = strdup(value);
225 
226 			} else if (strcmp(key, "Alias") == 0) {
227 				free(adapter->name);
228 				adapter->name = strdup(value);
229 			}
230 
231 		} else if (type == DBUS_TYPE_UINT32) {
232 			uint32_t value;
233 
234 			dbus_message_iter_get_basic(&variant_iter, &value);
235 
236 			if (strcmp(key, "Class") == 0)
237 				adapter->bluetooth_class = value;
238 
239 		} else if (type == DBUS_TYPE_BOOLEAN) {
240 			int value;
241 
242 			dbus_message_iter_get_basic(&variant_iter, &value);
243 
244 			if (strcmp(key, "Powered") == 0)
245 				bt_adapter_set_powered(adapter, value);
246 		}
247 
248 		dbus_message_iter_next(properties_array_iter);
249 	}
250 
251 	while (invalidated_array_iter &&
252 	       dbus_message_iter_get_arg_type(invalidated_array_iter) !=
253 		       DBUS_TYPE_INVALID) {
254 		const char *key;
255 
256 		dbus_message_iter_get_basic(invalidated_array_iter, &key);
257 
258 		if (strcmp(key, "Address") == 0) {
259 			free(adapter->address);
260 			adapter->address = NULL;
261 		} else if (strcmp(key, "Alias") == 0) {
262 			free(adapter->name);
263 			adapter->name = NULL;
264 		} else if (strcmp(key, "Class") == 0) {
265 			adapter->bluetooth_class = 0;
266 		} else if (strcmp(key, "Powered") == 0) {
267 			adapter->powered = 0;
268 		}
269 
270 		dbus_message_iter_next(invalidated_array_iter);
271 	}
272 }
273 
cras_bt_adapter_on_usb(struct cras_bt_adapter * adapter)274 int cras_bt_adapter_on_usb(struct cras_bt_adapter *adapter)
275 {
276 	return !!(adapter->bus_type == HCI_USB);
277 }
278 
279 /*
280  * Expect to receive supported capabilities in reply, like below format:
281  * array [
282  *   dict entry(
283  *     string "wide band speech"
284  *     variant
285  *       boolean <value>
286  *   )
287  * ]
288  */
on_get_supported_capabilities_reply(DBusPendingCall * pending_call,void * data)289 static void on_get_supported_capabilities_reply(DBusPendingCall *pending_call,
290 						void *data)
291 {
292 	DBusMessage *reply;
293 	DBusMessageIter message_iter, capabilities;
294 	struct cras_bt_adapter *adapter;
295 
296 	reply = dbus_pending_call_steal_reply(pending_call);
297 	dbus_pending_call_unref(pending_call);
298 
299 	if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
300 		syslog(LOG_ERR,
301 		       "GetSupportedCapabilities message replied error: %s",
302 		       dbus_message_get_error_name(reply));
303 		goto get_supported_capabilities_err;
304 	}
305 
306 	if (!dbus_message_iter_init(reply, &message_iter)) {
307 		syslog(LOG_ERR, "GetSupportedCapabilities reply doesn't have"
308 				"argument");
309 		goto get_supported_capabilities_err;
310 	}
311 
312 	DL_FOREACH (adapters, adapter) {
313 		if (adapter == (struct cras_bt_adapter *)data)
314 			break;
315 	}
316 	if (NULL == adapter)
317 		goto get_supported_capabilities_err;
318 
319 	dbus_message_iter_recurse(&message_iter, &capabilities);
320 
321 	while (dbus_message_iter_get_arg_type(&capabilities) !=
322 	       DBUS_TYPE_INVALID) {
323 		DBusMessageIter cap_dict_iter, variant_iter;
324 		const char *key;
325 		int type;
326 
327 		dbus_message_iter_recurse(&capabilities, &cap_dict_iter);
328 
329 		dbus_message_iter_get_basic(&cap_dict_iter, &key);
330 		dbus_message_iter_next(&cap_dict_iter);
331 
332 		dbus_message_iter_recurse(&cap_dict_iter, &variant_iter);
333 		type = dbus_message_iter_get_arg_type(&variant_iter);
334 
335 		if (type == DBUS_TYPE_BOOLEAN) {
336 			int value;
337 
338 			dbus_message_iter_get_basic(&variant_iter, &value);
339 
340 			if (strcmp(key, "wide band speech") == 0)
341 				adapter->wide_band_speech = value;
342 		}
343 
344 		dbus_message_iter_next(&capabilities);
345 	}
346 
347 get_supported_capabilities_err:
348 	dbus_message_unref(reply);
349 }
350 
cras_bt_adapter_get_supported_capabilities(struct cras_bt_adapter * adapter)351 int cras_bt_adapter_get_supported_capabilities(struct cras_bt_adapter *adapter)
352 {
353 	DBusMessage *method_call;
354 	DBusError dbus_error;
355 	DBusPendingCall *pending_call;
356 
357 	method_call = dbus_message_new_method_call(BLUEZ_SERVICE,
358 						   adapter->object_path,
359 						   BLUEZ_INTERFACE_ADAPTER,
360 						   "GetSupportedCapabilities");
361 	if (!method_call)
362 		return -ENOMEM;
363 
364 	dbus_error_init(&dbus_error);
365 	if (!dbus_connection_send_with_reply(adapter->conn, method_call,
366 					     &pending_call,
367 					     DBUS_TIMEOUT_USE_DEFAULT)) {
368 		dbus_message_unref(method_call);
369 		syslog(LOG_ERR,
370 		       "Failed to send GetSupportedCapabilities message");
371 		return -EIO;
372 	}
373 
374 	dbus_message_unref(method_call);
375 	if (!dbus_pending_call_set_notify(pending_call,
376 					  on_get_supported_capabilities_reply,
377 					  adapter, NULL)) {
378 		dbus_pending_call_cancel(pending_call);
379 		dbus_pending_call_unref(pending_call);
380 		return -EIO;
381 	}
382 	return 0;
383 }
384