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}