1 /*
2 * Copyright 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "btif_hci_vs.h"
18
19 #include <bluetooth/log.h>
20
21 #include "btif_common.h"
22 #include "hci/hci_interface.h"
23 #include "main/shim/entry.h"
24 #include "packet/raw_builder.h"
25 #include "stack/include/main_thread.h"
26
27 namespace bluetooth {
28 namespace hci_vs {
29
30 using hci::CommandCompleteView;
31 using hci::CommandStatusOrCompleteView;
32 using hci::CommandStatusView;
33 using hci::OpCode;
34 using hci::VendorSpecificEventView;
35
36 std::unique_ptr<BluetoothHciVendorSpecificInterface> hciVendorSpecificInterface;
37
CommandStatusOrCompleteCallback(BluetoothHciVendorSpecificCallbacks * callbacks,Cookie cookie,CommandStatusOrCompleteView status_or_complete)38 static void CommandStatusOrCompleteCallback(BluetoothHciVendorSpecificCallbacks* callbacks,
39 Cookie cookie,
40 CommandStatusOrCompleteView status_or_complete) {
41 if (std::holds_alternative<CommandStatusView>(status_or_complete)) {
42 auto view = std::get<CommandStatusView>(status_or_complete);
43 auto ocf = static_cast<uint16_t>(view.GetCommandOpCode()) & 0x3ff;
44 auto status = static_cast<uint8_t>(view.GetStatus());
45 do_in_jni_thread(base::BindOnce(&BluetoothHciVendorSpecificCallbacks::onCommandStatus,
46 base::Unretained(callbacks), ocf, status, cookie));
47
48 } else if (std::holds_alternative<CommandCompleteView>(status_or_complete)) {
49 auto view = std::get<CommandCompleteView>(status_or_complete);
50 auto ocf = static_cast<uint16_t>(view.GetCommandOpCode()) & 0x3ff;
51 std::vector<uint8_t> return_parameters(view.GetPayload().begin(), view.GetPayload().end());
52 do_in_jni_thread(base::BindOnce(&BluetoothHciVendorSpecificCallbacks::onCommandComplete,
53 base::Unretained(callbacks), ocf, return_parameters, cookie));
54 }
55 }
56
EventCallback(BluetoothHciVendorSpecificCallbacks * callbacks,VendorSpecificEventView view)57 static void EventCallback(BluetoothHciVendorSpecificCallbacks* callbacks,
58 VendorSpecificEventView view) {
59 const uint8_t aosp_reserved_codes_range[] = {0x50, 0x60};
60 auto code = static_cast<uint8_t>(view.GetSubeventCode());
61 if (code >= aosp_reserved_codes_range[0] && code < aosp_reserved_codes_range[1]) {
62 return;
63 }
64
65 std::vector<uint8_t> data(view.GetPayload().begin(), view.GetPayload().end());
66 do_in_jni_thread(base::BindOnce(&BluetoothHciVendorSpecificCallbacks::onEvent,
67 base::Unretained(callbacks), code, data));
68 }
69
70 class BluetoothHciVendorSpecificInterfaceImpl
71 : public bluetooth::hci_vs::BluetoothHciVendorSpecificInterface {
72 ~BluetoothHciVendorSpecificInterfaceImpl() override = default;
73
init(BluetoothHciVendorSpecificCallbacks * callbacks)74 void init(BluetoothHciVendorSpecificCallbacks* callbacks) override {
75 log::info("BluetoothHciVendorSpecificInterfaceImpl");
76 log::assert_that(callbacks != nullptr, "callbacks cannot be null");
77 callbacks_ = callbacks;
78
79 shim::GetHciLayer()->RegisterDefaultVendorSpecificEventHandler(
80 get_main()->Bind(EventCallback, callbacks_));
81 }
82
sendCommand(uint16_t ocf,std::vector<uint8_t> parameters,Cookie cookie)83 void sendCommand(uint16_t ocf, std::vector<uint8_t> parameters, Cookie cookie) override {
84 if (callbacks_ == nullptr) {
85 log::error("not initialized");
86 return;
87 }
88
89 if (ocf & ~0x3ff) {
90 log::error("invalid vendor-specific op-code");
91 return;
92 }
93
94 const uint16_t ogf_vendor_specific = 0x3f;
95 auto op_code = static_cast<OpCode>((ogf_vendor_specific << 10) | ocf);
96
97 shim::GetHciLayer()->EnqueueCommand(
98 hci::CommandBuilder::Create(
99 op_code, std::make_unique<packet::RawBuilder>(std::move(parameters))),
100 get_main()->BindOnce(CommandStatusOrCompleteCallback, callbacks_, std::move(cookie)));
101 }
102
103 private:
104 BluetoothHciVendorSpecificCallbacks* callbacks_ = nullptr;
105 };
106
getBluetoothHciVendorSpecificInterface()107 BluetoothHciVendorSpecificInterface* getBluetoothHciVendorSpecificInterface() {
108 if (!hciVendorSpecificInterface) {
109 hciVendorSpecificInterface.reset(new BluetoothHciVendorSpecificInterfaceImpl());
110 }
111
112 return hciVendorSpecificInterface.get();
113 }
114
115 } // namespace hci_vs
116 } // namespace bluetooth
117