blob: ace76b34c6d8249a40fe5944196ef15847d0187c [file] [log] [blame]
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -07001/******************************************************************************
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
Marie Janssen49a86702015-07-08 11:48:57 -070021#include "vendor.h"
22
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070023#include <assert.h>
24#include <dlfcn.h>
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070025
Zach Johnsonbf8193b2014-09-08 09:56:35 -070026#include "buffer_allocator.h"
Sharvil Nanavati44802762014-12-23 23:08:58 -080027#include "osi/include/log.h"
Marie Janssen49a86702015-07-08 11:48:57 -070028#include "osi/include/osi.h"
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070029
Zach Johnsonfbbd42b2014-08-15 17:00:17 -070030#define LAST_VENDOR_OPCODE_VALUE VENDOR_DO_EPILOG
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070031
32static const char *VENDOR_LIBRARY_NAME = "libbt-vendor.so";
33static const char *VENDOR_LIBRARY_SYMBOL_NAME = "BLUETOOTH_VENDOR_LIB_INTERFACE";
34
Zach Johnsonbf8193b2014-09-08 09:56:35 -070035static const vendor_t interface;
36static const allocator_t *buffer_allocator;
37static const hci_t *hci;
Zach Johnsonfbbd42b2014-08-15 17:00:17 -070038static vendor_cb callbacks[LAST_VENDOR_OPCODE_VALUE + 1];
Zach Johnsonfbbd42b2014-08-15 17:00:17 -070039
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070040static void *lib_handle;
Zach Johnsonfbbd42b2014-08-15 17:00:17 -070041static bt_vendor_interface_t *lib_interface;
42static const bt_vendor_callbacks_t lib_callbacks;
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070043
Zach Johnsonfbbd42b2014-08-15 17:00:17 -070044// Interface functions
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070045
Zach Johnson218f3752014-09-03 14:36:44 -070046static bool vendor_open(
47 const uint8_t *local_bdaddr,
Zach Johnsonbf8193b2014-09-08 09:56:35 -070048 const hci_t *hci_interface) {
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070049 assert(lib_handle == NULL);
Zach Johnson218f3752014-09-03 14:36:44 -070050 hci = hci_interface;
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070051
52 lib_handle = dlopen(VENDOR_LIBRARY_NAME, RTLD_NOW);
53 if (!lib_handle) {
Marie Janssendb554582015-06-26 14:53:46 -070054 LOG_ERROR(LOG_TAG, "%s unable to open %s: %s", __func__, VENDOR_LIBRARY_NAME, dlerror());
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070055 goto error;
56 }
57
Zach Johnsonfbbd42b2014-08-15 17:00:17 -070058 lib_interface = (bt_vendor_interface_t *)dlsym(lib_handle, VENDOR_LIBRARY_SYMBOL_NAME);
59 if (!lib_interface) {
Marie Janssendb554582015-06-26 14:53:46 -070060 LOG_ERROR(LOG_TAG, "%s unable to find symbol %s in %s: %s", __func__, VENDOR_LIBRARY_SYMBOL_NAME, VENDOR_LIBRARY_NAME, dlerror());
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070061 goto error;
62 }
63
Marie Janssendb554582015-06-26 14:53:46 -070064 LOG_INFO(LOG_TAG, "alloc value %p", lib_callbacks.alloc);
Zach Johnsonfbbd42b2014-08-15 17:00:17 -070065
66 int status = lib_interface->init(&lib_callbacks, (unsigned char *)local_bdaddr);
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070067 if (status) {
Marie Janssendb554582015-06-26 14:53:46 -070068 LOG_ERROR(LOG_TAG, "%s unable to initialize vendor library: %d", __func__, status);
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070069 goto error;
70 }
71
72 return true;
73
74error:;
Zach Johnsonfbbd42b2014-08-15 17:00:17 -070075 lib_interface = NULL;
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070076 if (lib_handle)
77 dlclose(lib_handle);
78 lib_handle = NULL;
79 return false;
80}
81
Zach Johnsonfbbd42b2014-08-15 17:00:17 -070082static void vendor_close(void) {
83 if (lib_interface)
84 lib_interface->cleanup();
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070085
86 if (lib_handle)
87 dlclose(lib_handle);
88
Zach Johnsonfbbd42b2014-08-15 17:00:17 -070089 lib_interface = NULL;
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070090 lib_handle = NULL;
91}
92
Zach Johnsonfbbd42b2014-08-15 17:00:17 -070093static int send_command(vendor_opcode_t opcode, void *param) {
94 assert(lib_interface != NULL);
95 return lib_interface->op(opcode, param);
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -070096}
97
Zach Johnsonfbbd42b2014-08-15 17:00:17 -070098static 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
Zach Johnsonfbbd42b2014-08-15 17:00:17 -0700107// Internal functions
108
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700109// Called back from vendor library when the firmware configuration
110// completes.
111static void firmware_config_cb(bt_vendor_op_result_t result) {
Marie Janssendb554582015-06-26 14:53:46 -0700112 LOG_INFO(LOG_TAG, "firmware callback");
Zach Johnsonfbbd42b2014-08-15 17:00:17 -0700113 vendor_cb callback = callbacks[VENDOR_CONFIGURE_FIRMWARE];
114 assert(callback != NULL);
115 callback(result == BT_VND_OP_RESULT_SUCCESS);
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700116}
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.
Zach Johnsonfbbd42b2014-08-15 17:00:17 -0700121static void sco_config_cb(bt_vendor_op_result_t result) {
Marie Janssendb554582015-06-26 14:53:46 -0700122 LOG_INFO(LOG_TAG, "%s", __func__);
Zach Johnsonfbbd42b2014-08-15 17:00:17 -0700123 vendor_cb callback = callbacks[VENDOR_CONFIGURE_SCO];
124 assert(callback != NULL);
125 callback(result == BT_VND_OP_RESULT_SUCCESS);
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700126}
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) {
Marie Janssendb554582015-06-26 14:53:46 -0700131 LOG_INFO(LOG_TAG, "%s", __func__);
Zach Johnsonfbbd42b2014-08-15 17:00:17 -0700132 vendor_cb callback = callbacks[VENDOR_SET_LPM_MODE];
133 assert(callback != NULL);
134 callback(result == BT_VND_OP_RESULT_SUCCESS);
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700135}
136
Matthew Xie66432dc2014-04-27 05:45:32 -0700137/******************************************************************************
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
Marie Janssendb554582015-06-26 14:53:46 -0700152 LOG_INFO(LOG_TAG, "sco_audiostate_cb(status: %d)",status);
Matthew Xie66432dc2014-04-27 05:45:32 -0700153}
154
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700155// Called by vendor library when it needs an HCI buffer.
Chris Mantonfb5ab992014-07-31 09:22:09 -0700156static void *buffer_alloc_cb(int size) {
Zach Johnsonbf8193b2014-09-08 09:56:35 -0700157 return buffer_allocator->alloc(size);
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700158}
159
160// Called by vendor library when it needs to free a buffer allocated with
Chris Mantonfb5ab992014-07-31 09:22:09 -0700161// |buffer_alloc_cb|.
162static void buffer_free_cb(void *buffer) {
Zach Johnsonbf8193b2014-09-08 09:56:35 -0700163 buffer_allocator->free(buffer);
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700164}
165
Zach Johnson218f3752014-09-03 14:36:44 -0700166static void transmit_completed_callback(BT_HDR *response, void *context) {
Zach Johnsoncab78162014-10-16 15:52:45 -0700167 // Call back to the vendor library if it provided a callback to call.
168 if (context)
169 ((tINT_CMD_CBACK)context)(response);
Zach Johnson218f3752014-09-03 14:36:44 -0700170}
171
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700172// Called back from vendor library when it wants to send an HCI command.
Zach Johnson218f3752014-09-03 14:36:44 -0700173static 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;
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700177}
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.
Zach Johnsonfbbd42b2014-08-15 17:00:17 -0700182static void epilog_cb(bt_vendor_op_result_t result) {
Marie Janssendb554582015-06-26 14:53:46 -0700183 LOG_INFO(LOG_TAG, "%s", __func__);
Zach Johnsonfbbd42b2014-08-15 17:00:17 -0700184 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
Zach Johnsonbf8193b2014-09-08 09:56:35 -0700201static const vendor_t interface = {
Zach Johnsonfbbd42b2014-08-15 17:00:17 -0700202 vendor_open,
203 vendor_close,
204 send_command,
205 send_async_command,
206 set_callback,
Zach Johnsonfbbd42b2014-08-15 17:00:17 -0700207};
208
Zach Johnsonbf8193b2014-09-08 09:56:35 -0700209const vendor_t *vendor_get_interface() {
210 buffer_allocator = buffer_allocator_get_interface();
Zach Johnsonfbbd42b2014-08-15 17:00:17 -0700211 return &interface;
Sharvil Nanavatif3b23f22014-06-15 13:36:45 -0700212}