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