Home | History | Annotate | Download | only in server
      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 
     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 
     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 
     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 
    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 
    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 
    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 
    150 const char *cras_bt_adapter_object_path(const struct cras_bt_adapter *adapter)
    151 {
    152 	return adapter->object_path;
    153 }
    154 
    155 const char *cras_bt_adapter_address(const struct cras_bt_adapter *adapter)
    156 {
    157 	return adapter->address;
    158 }
    159 
    160 const char *cras_bt_adapter_name(const struct cras_bt_adapter *adapter)
    161 {
    162 	return adapter->name;
    163 }
    164 
    165 int cras_bt_adapter_powered(const struct cras_bt_adapter *adapter)
    166 {
    167 	return adapter->powered;
    168 }
    169 
    170 
    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 
    249 int cras_bt_adapter_on_usb(struct cras_bt_adapter *adapter)
    250 {
    251 	return !!(adapter->bus_type == HCI_USB);
    252 }