1/****************************************************************************** 2 * 3 * Copyright (C) 2014 Google, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19#define LOG_TAG "bt_vendor" 20 21#include <assert.h> 22#include <dlfcn.h> 23 24#include "buffer_allocator.h" 25#include "bt_vendor_lib.h" 26#include "osi/include/osi.h" 27#include "osi/include/log.h" 28#include "vendor.h" 29 30#define LAST_VENDOR_OPCODE_VALUE VENDOR_DO_EPILOG 31 32static const char *VENDOR_LIBRARY_NAME = "libbt-vendor.so"; 33static const char *VENDOR_LIBRARY_SYMBOL_NAME = "BLUETOOTH_VENDOR_LIB_INTERFACE"; 34 35static const vendor_t interface; 36static const allocator_t *buffer_allocator; 37static const hci_t *hci; 38static vendor_cb callbacks[LAST_VENDOR_OPCODE_VALUE + 1]; 39 40static void *lib_handle; 41static bt_vendor_interface_t *lib_interface; 42static const bt_vendor_callbacks_t lib_callbacks; 43 44// Interface functions 45 46static bool vendor_open( 47 const uint8_t *local_bdaddr, 48 const hci_t *hci_interface) { 49 assert(lib_handle == NULL); 50 hci = hci_interface; 51 52 lib_handle = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW); 53 if (!lib_handle) { 54 LOG_ERROR("%s unable to open %s: %s", __func__, VENDOR_LIBRARY_NAME, dlerror()); 55 goto error; 56 } 57 58 lib_interface = (bt_vendor_interface_t *)dlsym(lib_handle, VENDOR_LIBRARY_SYMBOL_NAME); 59 if (!lib_interface) { 60 LOG_ERROR("%s unable to find symbol %s in %s: %s", __func__, VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror()); 61 goto error; 62 } 63 64 LOG_INFO("alloc value %p", lib_callbacks.alloc); 65 66 int status = lib_interface->init(&lib_callbacks, (unsigned char *)local_bdaddr); 67 if (status) { 68 LOG_ERROR("%s unable to initialize vendor library: %d", __func__, status); 69 goto error; 70 } 71 72 return true; 73 74error:; 75 lib_interface = NULL; 76 if (lib_handle) 77 dlclose(lib_handle); 78 lib_handle = NULL; 79 return false; 80} 81 82static void vendor_close(void) { 83 if (lib_interface) 84 lib_interface->cleanup(); 85 86 if (lib_handle) 87 dlclose(lib_handle); 88 89 lib_interface = NULL; 90 lib_handle = NULL; 91} 92 93static int send_command(vendor_opcode_t opcode, void *param) { 94 assert(lib_interface != NULL); 95 return lib_interface->op(opcode, param); 96} 97 98static int send_async_command(vendor_async_opcode_t opcode, void *param) { 99 assert(lib_interface != NULL); 100 return lib_interface->op(opcode, param); 101} 102 103static void set_callback(vendor_async_opcode_t opcode, vendor_cb callback) { 104 callbacks[opcode] = callback; 105} 106 107// Internal functions 108 109// Called back from vendor library when the firmware configuration 110// completes. 111static void firmware_config_cb(bt_vendor_op_result_t result) { 112 LOG_INFO("firmware callback"); 113 vendor_cb callback = callbacks[VENDOR_CONFIGURE_FIRMWARE]; 114 assert(callback != NULL); 115 callback(result == BT_VND_OP_RESULT_SUCCESS); 116} 117 118// Called back from vendor library to indicate status of previous 119// SCO configuration request. This should only happen during the 120// postload process. 121static void sco_config_cb(bt_vendor_op_result_t result) { 122 LOG_INFO("%s", __func__); 123 vendor_cb callback = callbacks[VENDOR_CONFIGURE_SCO]; 124 assert(callback != NULL); 125 callback(result == BT_VND_OP_RESULT_SUCCESS); 126} 127 128// Called back from vendor library to indicate status of previous 129// LPM enable/disable request. 130static void low_power_mode_cb(bt_vendor_op_result_t result) { 131 LOG_INFO("%s", __func__); 132 vendor_cb callback = callbacks[VENDOR_SET_LPM_MODE]; 133 assert(callback != NULL); 134 callback(result == BT_VND_OP_RESULT_SUCCESS); 135} 136 137/****************************************************************************** 138** 139** Function sco_audiostate_cb 140** 141** Description HOST/CONTROLLER VENDOR LIB CALLBACK API - This function is 142** called when the libbt-vendor completed vendor specific codec 143** setup request 144** 145** Returns None 146** 147******************************************************************************/ 148static void sco_audiostate_cb(bt_vendor_op_result_t result) 149{ 150 uint8_t status = (result == BT_VND_OP_RESULT_SUCCESS) ? 0 : 1; 151 152 LOG_INFO("sco_audiostate_cb(status: %d)",status); 153} 154 155// Called by vendor library when it needs an HCI buffer. 156static void *buffer_alloc_cb(int size) { 157 return buffer_allocator->alloc(size); 158} 159 160// Called by vendor library when it needs to free a buffer allocated with 161// |buffer_alloc_cb|. 162static void buffer_free_cb(void *buffer) { 163 buffer_allocator->free(buffer); 164} 165 166static void transmit_completed_callback(BT_HDR *response, void *context) { 167 // Call back to the vendor library if it provided a callback to call. 168 if (context) 169 ((tINT_CMD_CBACK)context)(response); 170} 171 172// Called back from vendor library when it wants to send an HCI command. 173static uint8_t transmit_cb(UNUSED_ATTR uint16_t opcode, void *buffer, tINT_CMD_CBACK callback) { 174 assert(hci != NULL); 175 hci->transmit_command((BT_HDR *)buffer, transmit_completed_callback, NULL, callback); 176 return true; 177} 178 179// Called back from vendor library when the epilog procedure has 180// completed. It is safe to call vendor_interface->cleanup() after 181// this callback has been received. 182static void epilog_cb(bt_vendor_op_result_t result) { 183 LOG_INFO("%s", __func__); 184 vendor_cb callback = callbacks[VENDOR_DO_EPILOG]; 185 assert(callback != NULL); 186 callback(result == BT_VND_OP_RESULT_SUCCESS); 187} 188 189static const bt_vendor_callbacks_t lib_callbacks = { 190 sizeof(lib_callbacks), 191 firmware_config_cb, 192 sco_config_cb, 193 low_power_mode_cb, 194 sco_audiostate_cb, 195 buffer_alloc_cb, 196 buffer_free_cb, 197 transmit_cb, 198 epilog_cb 199}; 200 201static const vendor_t interface = { 202 vendor_open, 203 vendor_close, 204 send_command, 205 send_async_command, 206 set_callback, 207}; 208 209const vendor_t *vendor_get_interface() { 210 buffer_allocator = buffer_allocator_get_interface(); 211 return &interface; 212} 213