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 }