1 use crate::bindings::root as bindings;
2 use crate::btif::{BluetoothInterface, BtStatus, RawAddress, SupportedProfiles, ToggleableProfile};
3 use crate::ccall;
4 use crate::profiles::hid_host::bindings::bthh_interface_t;
5 use crate::topstack::get_dispatchers;
6 use crate::utils::LTCheckedPtrMut;
7
8 use num_derive::{FromPrimitive, ToPrimitive};
9 use num_traits::cast::{FromPrimitive, ToPrimitive};
10 use std::sync::{Arc, Mutex};
11 use topshim_macros::{cb_variant, profile_enabled_or};
12
13 use log::warn;
14
15 #[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
16 #[repr(u32)]
17 pub enum BthhConnectionState {
18 Connected = 0,
19 Connecting,
20 Disconnected,
21 Disconnecting,
22 Unknown = 0xff,
23 }
24
25 impl From<bindings::bthh_connection_state_t> for BthhConnectionState {
from(item: bindings::bthh_connection_state_t) -> Self26 fn from(item: bindings::bthh_connection_state_t) -> Self {
27 BthhConnectionState::from_u32(item).unwrap_or_else(|| BthhConnectionState::Unknown)
28 }
29 }
30
31 #[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
32 #[repr(u32)]
33 pub enum BthhStatus {
34 Ok = 0,
35 HsHidNotReady,
36 HsInvalidRptId,
37 HsTransNotSpt,
38 HsInvalidParam,
39 HsError,
40 Error,
41 ErrSdp,
42 ErrProto,
43 ErrDbFull,
44 ErrTodUnspt,
45 ErrNoRes,
46 ErrAuthFailed,
47 ErrHdl,
48
49 Unknown,
50 }
51
52 impl From<bindings::bthh_status_t> for BthhStatus {
from(item: bindings::bthh_status_t) -> Self53 fn from(item: bindings::bthh_status_t) -> Self {
54 BthhStatus::from_u32(item).unwrap_or_else(|| BthhStatus::Unknown)
55 }
56 }
57
58 pub type BthhHidInfo = bindings::bthh_hid_info_t;
59
60 #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
61 #[repr(u32)]
62 pub enum BthhProtocolMode {
63 ReportMode = 0,
64 BootMode = 1,
65 UnsupportedMode = 0xff,
66 }
67
68 impl From<bindings::bthh_protocol_mode_t> for BthhProtocolMode {
from(item: bindings::bthh_protocol_mode_t) -> Self69 fn from(item: bindings::bthh_protocol_mode_t) -> Self {
70 BthhProtocolMode::from_u32(item).unwrap_or_else(|| BthhProtocolMode::UnsupportedMode)
71 }
72 }
73
74 impl From<BthhProtocolMode> for bindings::bthh_protocol_mode_t {
from(item: BthhProtocolMode) -> Self75 fn from(item: BthhProtocolMode) -> Self {
76 item.to_u32().unwrap()
77 }
78 }
79
80 #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
81 #[repr(u32)]
82 pub enum BthhReportType {
83 InputReport = 1,
84 OutputReport = 2,
85 FeatureReport = 3,
86 }
87
88 impl From<BthhReportType> for bindings::bthh_report_type_t {
from(item: BthhReportType) -> Self89 fn from(item: BthhReportType) -> Self {
90 item.to_u32().unwrap()
91 }
92 }
93
convert_report(count: i32, raw: *mut u8) -> Vec<u8>94 fn convert_report(count: i32, raw: *mut u8) -> Vec<u8> {
95 let mut v: Vec<u8> = Vec::new();
96 for i in 0..isize::from_i32(count).unwrap() {
97 let p: *const u8 = unsafe { raw.offset(i) };
98 v.push(unsafe { *p });
99 }
100
101 return v;
102 }
103
104 #[derive(Debug)]
105 pub enum HHCallbacks {
106 ConnectionState(RawAddress, BthhConnectionState),
107 VirtualUnplug(RawAddress, BthhStatus),
108 HidInfo(RawAddress, BthhHidInfo),
109 ProtocolMode(RawAddress, BthhStatus, BthhProtocolMode),
110 IdleTime(RawAddress, BthhStatus, i32),
111 GetReport(RawAddress, BthhStatus, Vec<u8>, i32),
112 Handshake(RawAddress, BthhStatus),
113 }
114
115 pub struct HHCallbacksDispatcher {
116 pub dispatch: Box<dyn Fn(HHCallbacks) + Send>,
117 }
118
119 type HHCb = Arc<Mutex<HHCallbacksDispatcher>>;
120
121 cb_variant!(HHCb, connection_state_cb -> HHCallbacks::ConnectionState,
122 *mut RawAddress, bindings::bthh_connection_state_t -> BthhConnectionState, {
123 let _0 = unsafe { *_0 };
124 });
125 cb_variant!(HHCb, virtual_unplug_cb -> HHCallbacks::VirtualUnplug,
126 *mut RawAddress, bindings::bthh_status_t -> BthhStatus, {
127 let _0 = unsafe { *_0 };
128 });
129 cb_variant!(HHCb, hid_info_cb -> HHCallbacks::HidInfo,
130 *mut RawAddress, bindings::bthh_hid_info_t -> BthhHidInfo, {
131 let _0 = unsafe { *_0 };
132 });
133 cb_variant!(HHCb, protocol_mode_cb -> HHCallbacks::ProtocolMode,
134 *mut RawAddress, bindings::bthh_status_t -> BthhStatus,
135 bindings::bthh_protocol_mode_t -> BthhProtocolMode, {
136 let _0 = unsafe { *_0 };
137 });
138 cb_variant!(HHCb, idle_time_cb -> HHCallbacks::IdleTime,
139 *mut RawAddress, bindings::bthh_status_t -> BthhStatus, i32, {
140 let _0 = unsafe { *_0 };
141 });
142 cb_variant!(HHCb, get_report_cb -> HHCallbacks::GetReport,
143 *mut RawAddress, bindings::bthh_status_t -> BthhStatus, *mut u8, i32, {
144 let _0 = unsafe { *_0 };
145 let _2 = convert_report(_3, _2);
146 });
147 cb_variant!(HHCb, handshake_cb -> HHCallbacks::Handshake,
148 *mut RawAddress, bindings::bthh_status_t -> BthhStatus, {
149 let _0 = unsafe { *_0 };
150 });
151
152 struct RawHHWrapper {
153 raw: *const bindings::bthh_interface_t,
154 }
155
156 // Pointers unsafe due to ownership but this is a static pointer so Send is ok
157 unsafe impl Send for RawHHWrapper {}
158
159 pub struct HidHost {
160 internal: RawHHWrapper,
161 is_init: bool,
162 _is_enabled: bool,
163 pub is_hogp_activated: bool,
164 pub is_hidp_activated: bool,
165 pub is_profile_updated: bool,
166 // Keep callback object in memory (underlying code doesn't make copy)
167 callbacks: Option<Box<bindings::bthh_callbacks_t>>,
168 }
169
170 impl ToggleableProfile for HidHost {
is_enabled(&self) -> bool171 fn is_enabled(&self) -> bool {
172 self._is_enabled
173 }
174
enable(&mut self) -> bool175 fn enable(&mut self) -> bool {
176 let cb_ptr = LTCheckedPtrMut::from(self.callbacks.as_mut().unwrap());
177
178 let init = ccall!(self, init, cb_ptr.into());
179 self.is_init = BtStatus::from(init) == BtStatus::Success;
180 self._is_enabled = self.is_init;
181 true
182 }
183
184 #[profile_enabled_or(false)]
disable(&mut self) -> bool185 fn disable(&mut self) -> bool {
186 ccall!(self, cleanup);
187 self._is_enabled = false;
188 true
189 }
190 }
191
192 impl HidHost {
new(intf: &BluetoothInterface) -> HidHost193 pub fn new(intf: &BluetoothInterface) -> HidHost {
194 let r = intf.get_profile_interface(SupportedProfiles::HidHost);
195 HidHost {
196 internal: RawHHWrapper { raw: r as *const bthh_interface_t },
197 is_init: false,
198 _is_enabled: false,
199 is_hogp_activated: false,
200 is_hidp_activated: false,
201 is_profile_updated: false,
202 callbacks: None,
203 }
204 }
205
is_initialized(&self) -> bool206 pub fn is_initialized(&self) -> bool {
207 self.is_init
208 }
209
initialize(&mut self, callbacks: HHCallbacksDispatcher) -> bool210 pub fn initialize(&mut self, callbacks: HHCallbacksDispatcher) -> bool {
211 // Register dispatcher
212 if get_dispatchers().lock().unwrap().set::<HHCb>(Arc::new(Mutex::new(callbacks))) {
213 panic!("Tried to set dispatcher for HHCallbacks but it already existed");
214 }
215
216 let callbacks = Box::new(bindings::bthh_callbacks_t {
217 size: 8 * 8,
218 connection_state_cb: Some(connection_state_cb),
219 hid_info_cb: Some(hid_info_cb),
220 protocol_mode_cb: Some(protocol_mode_cb),
221 idle_time_cb: Some(idle_time_cb),
222 get_report_cb: Some(get_report_cb),
223 virtual_unplug_cb: Some(virtual_unplug_cb),
224 handshake_cb: Some(handshake_cb),
225 });
226
227 self.callbacks = Some(callbacks);
228
229 true
230 }
231
232 #[profile_enabled_or(BtStatus::NotReady)]
connect(&self, addr: &mut RawAddress) -> BtStatus233 pub fn connect(&self, addr: &mut RawAddress) -> BtStatus {
234 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
235 BtStatus::from(ccall!(self, connect, addr_ptr.into()))
236 }
237
238 #[profile_enabled_or(BtStatus::NotReady)]
disconnect(&self, addr: &mut RawAddress) -> BtStatus239 pub fn disconnect(&self, addr: &mut RawAddress) -> BtStatus {
240 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
241 BtStatus::from(ccall!(self, disconnect, addr_ptr.into()))
242 }
243
244 #[profile_enabled_or(BtStatus::NotReady)]
virtual_unplug(&self, addr: &mut RawAddress) -> BtStatus245 pub fn virtual_unplug(&self, addr: &mut RawAddress) -> BtStatus {
246 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
247 BtStatus::from(ccall!(self, virtual_unplug, addr_ptr.into()))
248 }
249
250 #[profile_enabled_or(BtStatus::NotReady)]
set_info(&self, addr: &mut RawAddress, info: BthhHidInfo) -> BtStatus251 pub fn set_info(&self, addr: &mut RawAddress, info: BthhHidInfo) -> BtStatus {
252 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
253 BtStatus::from(ccall!(self, set_info, addr_ptr.into(), info))
254 }
255
256 #[profile_enabled_or(BtStatus::NotReady)]
get_protocol(&self, addr: &mut RawAddress, mode: BthhProtocolMode) -> BtStatus257 pub fn get_protocol(&self, addr: &mut RawAddress, mode: BthhProtocolMode) -> BtStatus {
258 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
259 BtStatus::from(ccall!(
260 self,
261 get_protocol,
262 addr_ptr.into(),
263 bindings::bthh_protocol_mode_t::from(mode)
264 ))
265 }
266
267 #[profile_enabled_or(BtStatus::NotReady)]
set_protocol(&self, addr: &mut RawAddress, mode: BthhProtocolMode) -> BtStatus268 pub fn set_protocol(&self, addr: &mut RawAddress, mode: BthhProtocolMode) -> BtStatus {
269 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
270 BtStatus::from(ccall!(
271 self,
272 set_protocol,
273 addr_ptr.into(),
274 bindings::bthh_protocol_mode_t::from(mode)
275 ))
276 }
277
278 #[profile_enabled_or(BtStatus::NotReady)]
get_idle_time(&self, addr: &mut RawAddress) -> BtStatus279 pub fn get_idle_time(&self, addr: &mut RawAddress) -> BtStatus {
280 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
281 BtStatus::from(ccall!(self, get_idle_time, addr_ptr.into()))
282 }
283
284 #[profile_enabled_or(BtStatus::NotReady)]
set_idle_time(&self, addr: &mut RawAddress, idle_time: u8) -> BtStatus285 pub fn set_idle_time(&self, addr: &mut RawAddress, idle_time: u8) -> BtStatus {
286 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
287 BtStatus::from(ccall!(self, set_idle_time, addr_ptr.into(), idle_time))
288 }
289
290 #[profile_enabled_or(BtStatus::NotReady)]
get_report( &self, addr: &mut RawAddress, report_type: BthhReportType, report_id: u8, buffer_size: i32, ) -> BtStatus291 pub fn get_report(
292 &self,
293 addr: &mut RawAddress,
294 report_type: BthhReportType,
295 report_id: u8,
296 buffer_size: i32,
297 ) -> BtStatus {
298 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
299 BtStatus::from(ccall!(
300 self,
301 get_report,
302 addr_ptr.into(),
303 bindings::bthh_report_type_t::from(report_type),
304 report_id,
305 buffer_size
306 ))
307 }
308
309 #[profile_enabled_or(BtStatus::NotReady)]
get_report_reply( &self, addr: &mut RawAddress, status: BthhStatus, report: &mut [u8], size: u16, ) -> BtStatus310 pub fn get_report_reply(
311 &self,
312 addr: &mut RawAddress,
313 status: BthhStatus,
314 report: &mut [u8],
315 size: u16,
316 ) -> BtStatus {
317 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
318 BtStatus::from(ccall!(
319 self,
320 get_report_reply,
321 addr_ptr.into(),
322 status as bindings::bthh_status_t,
323 report.as_mut_ptr() as *mut std::os::raw::c_char,
324 size
325 ))
326 }
327
328 #[profile_enabled_or(BtStatus::NotReady)]
set_report( &self, addr: &mut RawAddress, report_type: BthhReportType, report: &mut [u8], ) -> BtStatus329 pub fn set_report(
330 &self,
331 addr: &mut RawAddress,
332 report_type: BthhReportType,
333 report: &mut [u8],
334 ) -> BtStatus {
335 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
336 let report_ptr = LTCheckedPtrMut::from(report);
337 BtStatus::from(ccall!(
338 self,
339 set_report,
340 addr_ptr.into(),
341 bindings::bthh_report_type_t::from(report_type),
342 report_ptr.cast_into::<std::os::raw::c_char>()
343 ))
344 }
345
346 #[profile_enabled_or(BtStatus::NotReady)]
send_data(&mut self, addr: &mut RawAddress, data: &mut [u8]) -> BtStatus347 pub fn send_data(&mut self, addr: &mut RawAddress, data: &mut [u8]) -> BtStatus {
348 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
349 let data_ptr = LTCheckedPtrMut::from(data);
350 BtStatus::from(ccall!(
351 self,
352 send_data,
353 addr_ptr.into(),
354 data_ptr.cast_into::<std::os::raw::c_char>()
355 ))
356 }
357
358 /// return true if we need to restart hh
configure_enabled_profiles(&mut self) -> bool359 pub fn configure_enabled_profiles(&mut self) -> bool {
360 let needs_restart = self.is_profile_updated;
361 if self.is_profile_updated {
362 ccall!(
363 self,
364 configure_enabled_profiles,
365 self.is_hidp_activated,
366 self.is_hogp_activated
367 );
368 self.is_profile_updated = false;
369 }
370 needs_restart
371 }
372
activate_hogp(&mut self, active: bool)373 pub fn activate_hogp(&mut self, active: bool) {
374 if self.is_hogp_activated != active {
375 self.is_hogp_activated = active;
376 self.is_profile_updated = true;
377 }
378 }
379
activate_hidp(&mut self, active: bool)380 pub fn activate_hidp(&mut self, active: bool) {
381 if self.is_hidp_activated != active {
382 self.is_hidp_activated = active;
383 self.is_profile_updated = true;
384 }
385 }
386 #[profile_enabled_or]
cleanup(&mut self)387 pub fn cleanup(&mut self) {
388 ccall!(self, cleanup)
389 }
390 }
391