cras_bt_adapter.c revision 1668d94b1813ef49aae6dfce1d59fbeeafbf1b80
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
21struct 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
32static struct cras_bt_adapter *adapters;
33
34static 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.dev_id = atoi(pos + 3);
54	err = ioctl(ctl, HCIGETDEVINFO, (void *)&dev_info);
55	if (err) {
56		syslog(LOG_ERR, "HCI get dev info error %s", strerror(errno));
57		close(ctl);
58		return -1;
59	}
60	if ((dev_info.type & 0x0f) < HCI_BUS_MAX)
61		adapter->bus_type = (dev_info.type & 0x0f);
62
63	close(ctl);
64	return 0;
65}
66
67struct cras_bt_adapter *cras_bt_adapter_create(const char *object_path)
68{
69	struct cras_bt_adapter *adapter;
70
71	adapter = calloc(1, sizeof(*adapter));
72	if (adapter == NULL)
73		return NULL;
74
75	adapter->object_path = strdup(object_path);
76	if (adapter->object_path == NULL) {
77		free(adapter);
78		return NULL;
79	}
80
81	DL_APPEND(adapters, adapter);
82
83	/* Set bus type to USB as default when query fails. */
84	if (cras_bt_adapter_query_bus_type(adapter))
85		adapter->bus_type = HCI_USB;
86
87	return adapter;
88}
89
90void cras_bt_adapter_destroy(struct cras_bt_adapter *adapter)
91{
92	DL_DELETE(adapters, adapter);
93
94	free(adapter->object_path);
95	free(adapter->address);
96	free(adapter->name);
97	free(adapter);
98}
99
100void cras_bt_adapter_reset()
101{
102	while (adapters) {
103		syslog(LOG_INFO, "Bluetooth Adapter: %s removed",
104		       adapters->address);
105		cras_bt_adapter_destroy(adapters);
106	}
107}
108
109
110struct cras_bt_adapter *cras_bt_adapter_get(const char *object_path)
111{
112	struct cras_bt_adapter *adapter;
113
114	DL_FOREACH(adapters, adapter) {
115		if (strcmp(adapter->object_path, object_path) == 0)
116			return adapter;
117	}
118
119	return NULL;
120}
121
122size_t cras_bt_adapter_get_list(struct cras_bt_adapter ***adapter_list_out)
123{
124	struct cras_bt_adapter *adapter;
125	struct cras_bt_adapter **adapter_list = NULL;
126	size_t num_adapters = 0;
127
128	DL_FOREACH(adapters, adapter) {
129		struct cras_bt_adapter **tmp;
130
131		tmp = realloc(adapter_list,
132			      sizeof(adapter_list[0]) * (num_adapters + 1));
133		if (!tmp) {
134			free(adapter_list);
135			return -ENOMEM;
136		}
137
138		adapter_list = tmp;
139		adapter_list[num_adapters++] = adapter;
140	}
141
142	*adapter_list_out = adapter_list;
143	return num_adapters;
144}
145
146const char *cras_bt_adapter_object_path(const struct cras_bt_adapter *adapter)
147{
148	return adapter->object_path;
149}
150
151const char *cras_bt_adapter_address(const struct cras_bt_adapter *adapter)
152{
153	return adapter->address;
154}
155
156const char *cras_bt_adapter_name(const struct cras_bt_adapter *adapter)
157{
158	return adapter->name;
159}
160
161int cras_bt_adapter_powered(const struct cras_bt_adapter *adapter)
162{
163	return adapter->powered;
164}
165
166
167void cras_bt_adapter_update_properties(struct cras_bt_adapter *adapter,
168				       DBusMessageIter *properties_array_iter,
169				       DBusMessageIter *invalidated_array_iter)
170{
171	while (dbus_message_iter_get_arg_type(properties_array_iter) !=
172	       DBUS_TYPE_INVALID) {
173		DBusMessageIter properties_dict_iter, variant_iter;
174		const char *key;
175		int type;
176
177		dbus_message_iter_recurse(properties_array_iter,
178					  &properties_dict_iter);
179
180		dbus_message_iter_get_basic(&properties_dict_iter, &key);
181		dbus_message_iter_next(&properties_dict_iter);
182
183		dbus_message_iter_recurse(&properties_dict_iter, &variant_iter);
184		type = dbus_message_iter_get_arg_type(&variant_iter);
185
186		if (type == DBUS_TYPE_STRING) {
187			const char *value;
188
189			dbus_message_iter_get_basic(&variant_iter, &value);
190
191			if (strcmp(key, "Address") == 0) {
192				free(adapter->address);
193				adapter->address = strdup(value);
194
195			} else if (strcmp(key, "Alias") == 0) {
196				free(adapter->name);
197				adapter->name = strdup(value);
198
199			}
200
201		} else if (type == DBUS_TYPE_UINT32) {
202			uint32_t value;
203
204			dbus_message_iter_get_basic(&variant_iter, &value);
205
206			if (strcmp(key, "Class") == 0)
207				adapter->bluetooth_class = value;
208
209		} else if (type == DBUS_TYPE_BOOLEAN) {
210			int value;
211
212			dbus_message_iter_get_basic(&variant_iter, &value);
213
214			if (strcmp(key, "Powered") == 0)
215				adapter->powered = value;
216
217		}
218
219		dbus_message_iter_next(properties_array_iter);
220	}
221
222	while (invalidated_array_iter &&
223	       dbus_message_iter_get_arg_type(invalidated_array_iter) !=
224	       DBUS_TYPE_INVALID) {
225		const char *key;
226
227		dbus_message_iter_get_basic(invalidated_array_iter, &key);
228
229		if (strcmp(key, "Address") == 0) {
230			free(adapter->address);
231			adapter->address = NULL;
232		} else if (strcmp(key, "Alias") == 0) {
233			free(adapter->name);
234			adapter->name = NULL;
235		} else if (strcmp(key, "Class") == 0) {
236			adapter->bluetooth_class = 0;
237		} else if (strcmp(key, "Powered") == 0) {
238			adapter->powered = 0;
239		}
240
241		dbus_message_iter_next(invalidated_array_iter);
242	}
243}
244
245int cras_bt_adapter_on_usb(struct cras_bt_adapter *adapter)
246{
247	return !!(adapter->bus_type == HCI_USB);
248}