cras_bt_adapter.c revision 03d0bc67305029a07e5cfa3ea762c18d16718afc
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	if (object_path == NULL)
115		return NULL;
116
117	DL_FOREACH(adapters, adapter) {
118		if (strcmp(adapter->object_path, object_path) == 0)
119			return adapter;
120	}
121
122	return NULL;
123}
124
125size_t cras_bt_adapter_get_list(struct cras_bt_adapter ***adapter_list_out)
126{
127	struct cras_bt_adapter *adapter;
128	struct cras_bt_adapter **adapter_list = NULL;
129	size_t num_adapters = 0;
130
131	DL_FOREACH(adapters, adapter) {
132		struct cras_bt_adapter **tmp;
133
134		tmp = realloc(adapter_list,
135			      sizeof(adapter_list[0]) * (num_adapters + 1));
136		if (!tmp) {
137			free(adapter_list);
138			return -ENOMEM;
139		}
140
141		adapter_list = tmp;
142		adapter_list[num_adapters++] = adapter;
143	}
144
145	*adapter_list_out = adapter_list;
146	return num_adapters;
147}
148
149const char *cras_bt_adapter_object_path(const struct cras_bt_adapter *adapter)
150{
151	return adapter->object_path;
152}
153
154const char *cras_bt_adapter_address(const struct cras_bt_adapter *adapter)
155{
156	return adapter->address;
157}
158
159const char *cras_bt_adapter_name(const struct cras_bt_adapter *adapter)
160{
161	return adapter->name;
162}
163
164int cras_bt_adapter_powered(const struct cras_bt_adapter *adapter)
165{
166	return adapter->powered;
167}
168
169
170void cras_bt_adapter_update_properties(struct cras_bt_adapter *adapter,
171				       DBusMessageIter *properties_array_iter,
172				       DBusMessageIter *invalidated_array_iter)
173{
174	while (dbus_message_iter_get_arg_type(properties_array_iter) !=
175	       DBUS_TYPE_INVALID) {
176		DBusMessageIter properties_dict_iter, variant_iter;
177		const char *key;
178		int type;
179
180		dbus_message_iter_recurse(properties_array_iter,
181					  &properties_dict_iter);
182
183		dbus_message_iter_get_basic(&properties_dict_iter, &key);
184		dbus_message_iter_next(&properties_dict_iter);
185
186		dbus_message_iter_recurse(&properties_dict_iter, &variant_iter);
187		type = dbus_message_iter_get_arg_type(&variant_iter);
188
189		if (type == DBUS_TYPE_STRING) {
190			const char *value;
191
192			dbus_message_iter_get_basic(&variant_iter, &value);
193
194			if (strcmp(key, "Address") == 0) {
195				free(adapter->address);
196				adapter->address = strdup(value);
197
198			} else if (strcmp(key, "Alias") == 0) {
199				free(adapter->name);
200				adapter->name = strdup(value);
201
202			}
203
204		} else if (type == DBUS_TYPE_UINT32) {
205			uint32_t value;
206
207			dbus_message_iter_get_basic(&variant_iter, &value);
208
209			if (strcmp(key, "Class") == 0)
210				adapter->bluetooth_class = value;
211
212		} else if (type == DBUS_TYPE_BOOLEAN) {
213			int value;
214
215			dbus_message_iter_get_basic(&variant_iter, &value);
216
217			if (strcmp(key, "Powered") == 0)
218				adapter->powered = value;
219
220		}
221
222		dbus_message_iter_next(properties_array_iter);
223	}
224
225	while (invalidated_array_iter &&
226	       dbus_message_iter_get_arg_type(invalidated_array_iter) !=
227	       DBUS_TYPE_INVALID) {
228		const char *key;
229
230		dbus_message_iter_get_basic(invalidated_array_iter, &key);
231
232		if (strcmp(key, "Address") == 0) {
233			free(adapter->address);
234			adapter->address = NULL;
235		} else if (strcmp(key, "Alias") == 0) {
236			free(adapter->name);
237			adapter->name = NULL;
238		} else if (strcmp(key, "Class") == 0) {
239			adapter->bluetooth_class = 0;
240		} else if (strcmp(key, "Powered") == 0) {
241			adapter->powered = 0;
242		}
243
244		dbus_message_iter_next(invalidated_array_iter);
245	}
246}
247
248int cras_bt_adapter_on_usb(struct cras_bt_adapter *adapter)
249{
250	return !!(adapter->bus_type == HCI_USB);
251}