1 use crate::bindings::root as bindings;
2 use crate::btif::{
3 BluetoothInterface, BtAddrType, BtStatus, BtTransport, RawAddress, SupportedProfiles,
4 ToggleableProfile,
5 };
6 use crate::ccall;
7 use crate::profiles::hid_host::bindings::bthh_interface_t;
8 use crate::topstack::get_dispatchers;
9 use crate::utils::LTCheckedPtrMut;
10
11 use num_derive::{FromPrimitive, ToPrimitive};
12 use num_traits::cast::{FromPrimitive, ToPrimitive};
13 use std::fmt::{Debug, Formatter, Result};
14 use std::sync::{Arc, Mutex};
15 use topshim_macros::{cb_variant, log_args, profile_enabled_or};
16
17 use log::warn;
18
19 #[derive(Debug, FromPrimitive, PartialEq, PartialOrd, Copy, Clone)]
20 #[repr(u32)]
21 pub enum BthhConnectionState {
22 Connected = 0,
23 Connecting,
24 Disconnected,
25 Disconnecting,
26 Accepting,
27 Unknown = 0xff,
28 }
29
30 impl From<bindings::bthh_connection_state_t> for BthhConnectionState {
from(item: bindings::bthh_connection_state_t) -> Self31 fn from(item: bindings::bthh_connection_state_t) -> Self {
32 BthhConnectionState::from_u32(item).unwrap_or_else(|| BthhConnectionState::Unknown)
33 }
34 }
35
36 #[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
37 #[repr(u32)]
38 pub enum BthhStatus {
39 Ok = 0,
40 HsHidNotReady,
41 HsInvalidRptId,
42 HsTransNotSpt,
43 HsInvalidParam,
44 HsError,
45 Error,
46 ErrSdp,
47 ErrProto,
48 ErrDbFull,
49 ErrTodUnspt,
50 ErrNoRes,
51 ErrAuthFailed,
52 ErrHdl,
53
54 Unknown,
55 }
56
57 impl From<bindings::bthh_status_t> for BthhStatus {
from(item: bindings::bthh_status_t) -> Self58 fn from(item: bindings::bthh_status_t) -> Self {
59 BthhStatus::from_u32(item).unwrap_or_else(|| BthhStatus::Unknown)
60 }
61 }
62
63 pub type BthhHidInfo = bindings::bthh_hid_info_t;
64
65 #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
66 #[repr(u32)]
67 pub enum BthhProtocolMode {
68 ReportMode = 0,
69 BootMode = 1,
70 UnsupportedMode = 0xff,
71 }
72
73 impl From<bindings::bthh_protocol_mode_t> for BthhProtocolMode {
from(item: bindings::bthh_protocol_mode_t) -> Self74 fn from(item: bindings::bthh_protocol_mode_t) -> Self {
75 BthhProtocolMode::from_u32(item).unwrap_or_else(|| BthhProtocolMode::UnsupportedMode)
76 }
77 }
78
79 impl From<BthhProtocolMode> for bindings::bthh_protocol_mode_t {
from(item: BthhProtocolMode) -> Self80 fn from(item: BthhProtocolMode) -> Self {
81 item.to_u32().unwrap()
82 }
83 }
84
85 #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
86 #[repr(u32)]
87 pub enum BthhReportType {
88 InputReport = 1,
89 OutputReport = 2,
90 FeatureReport = 3,
91 }
92
93 impl From<BthhReportType> for bindings::bthh_report_type_t {
from(item: BthhReportType) -> Self94 fn from(item: BthhReportType) -> Self {
95 item.to_u32().unwrap()
96 }
97 }
98
convert_report(count: i32, raw: *mut u8) -> Vec<u8>99 fn convert_report(count: i32, raw: *mut u8) -> Vec<u8> {
100 let mut v: Vec<u8> = Vec::new();
101 for i in 0..isize::from_i32(count).unwrap() {
102 let p: *const u8 = unsafe { raw.offset(i) };
103 v.push(unsafe { *p });
104 }
105
106 return v;
107 }
108
109 #[derive(Debug)]
110 pub enum HHCallbacks {
111 ConnectionState(RawAddress, BtAddrType, BtTransport, BthhConnectionState),
112 VirtualUnplug(RawAddress, BtAddrType, BtTransport, BthhStatus),
113 HidInfo(RawAddress, BtAddrType, BtTransport, BthhHidInfo),
114 ProtocolMode(RawAddress, BtAddrType, BtTransport, BthhStatus, BthhProtocolMode),
115 IdleTime(RawAddress, BtAddrType, BtTransport, BthhStatus, i32),
116 GetReport(RawAddress, BtAddrType, BtTransport, BthhStatus, Vec<u8>, i32),
117 Handshake(RawAddress, BtAddrType, BtTransport, BthhStatus),
118 }
119
120 pub struct HHCallbacksDispatcher {
121 pub dispatch: Box<dyn Fn(HHCallbacks) + Send>,
122 }
123
124 impl Debug for HHCallbacksDispatcher {
fmt(&self, f: &mut Formatter<'_>) -> Result125 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
126 write!(f, "HHCallbacksDispatcher {{}}")
127 }
128 }
129
130 type HHCb = Arc<Mutex<HHCallbacksDispatcher>>;
131
132 cb_variant!(HHCb, connection_state_cb -> HHCallbacks::ConnectionState,
133 *mut RawAddress, u8 -> BtAddrType, u8 -> BtTransport, bindings::bthh_connection_state_t -> BthhConnectionState, {
134 let _0 = unsafe { *_0 };
135 });
136 cb_variant!(HHCb, virtual_unplug_cb -> HHCallbacks::VirtualUnplug,
137 *mut RawAddress, u8 -> BtAddrType, u8 -> BtTransport, bindings::bthh_status_t -> BthhStatus, {
138 let _0 = unsafe { *_0 };
139 });
140 cb_variant!(HHCb, hid_info_cb -> HHCallbacks::HidInfo,
141 *mut RawAddress, u8 -> BtAddrType, u8 -> BtTransport, bindings::bthh_hid_info_t -> BthhHidInfo, {
142 let _0 = unsafe { *_0 };
143 });
144 cb_variant!(HHCb, protocol_mode_cb -> HHCallbacks::ProtocolMode,
145 *mut RawAddress, u8 -> BtAddrType, u8 -> BtTransport, bindings::bthh_status_t -> BthhStatus,
146 bindings::bthh_protocol_mode_t -> BthhProtocolMode, {
147 let _0 = unsafe { *_0 };
148 });
149 cb_variant!(HHCb, idle_time_cb -> HHCallbacks::IdleTime,
150 *mut RawAddress, u8 -> BtAddrType, u8 -> BtTransport, bindings::bthh_status_t -> BthhStatus, i32, {
151 let _0 = unsafe { *_0 };
152 });
153 cb_variant!(HHCb, get_report_cb -> HHCallbacks::GetReport,
154 *mut RawAddress, u8 -> BtAddrType, u8 -> BtTransport, bindings::bthh_status_t -> BthhStatus, *mut u8, i32, {
155 let _0 = unsafe { *_0 };
156 let _4 = convert_report(_5, _4);
157 });
158 cb_variant!(HHCb, handshake_cb -> HHCallbacks::Handshake,
159 *mut RawAddress, u8 -> BtAddrType, u8 -> BtTransport, bindings::bthh_status_t -> BthhStatus, {
160 let _0 = unsafe { *_0 };
161 });
162
163 struct RawHHWrapper {
164 raw: *const bindings::bthh_interface_t,
165 }
166
167 // Pointers unsafe due to ownership but this is a static pointer so Send is ok
168 unsafe impl Send for RawHHWrapper {}
169
170 pub struct HidHost {
171 internal: RawHHWrapper,
172 is_init: bool,
173 _is_enabled: bool,
174 pub is_hogp_activated: bool,
175 pub is_hidp_activated: bool,
176 pub is_profile_updated: bool,
177 // Keep callback object in memory (underlying code doesn't make copy)
178 callbacks: Option<Box<bindings::bthh_callbacks_t>>,
179 }
180
181 impl ToggleableProfile for HidHost {
is_enabled(&self) -> bool182 fn is_enabled(&self) -> bool {
183 self._is_enabled
184 }
185
enable(&mut self) -> bool186 fn enable(&mut self) -> bool {
187 let cb_ptr = LTCheckedPtrMut::from(self.callbacks.as_mut().unwrap());
188
189 let init = ccall!(self, init, cb_ptr.into());
190 self.is_init = BtStatus::from(init) == BtStatus::Success;
191 self._is_enabled = self.is_init;
192 true
193 }
194
195 #[profile_enabled_or(false)]
disable(&mut self) -> bool196 fn disable(&mut self) -> bool {
197 ccall!(self, cleanup);
198 self._is_enabled = false;
199 true
200 }
201 }
202
203 impl HidHost {
204 #[log_args]
new(intf: &BluetoothInterface) -> HidHost205 pub fn new(intf: &BluetoothInterface) -> HidHost {
206 let r = intf.get_profile_interface(SupportedProfiles::HidHost);
207 HidHost {
208 internal: RawHHWrapper { raw: r as *const bthh_interface_t },
209 is_init: false,
210 _is_enabled: false,
211 is_hogp_activated: false,
212 is_hidp_activated: false,
213 is_profile_updated: false,
214 callbacks: None,
215 }
216 }
217
218 #[log_args]
is_initialized(&self) -> bool219 pub fn is_initialized(&self) -> bool {
220 self.is_init
221 }
222
223 #[log_args]
initialize(&mut self, callbacks: HHCallbacksDispatcher) -> bool224 pub fn initialize(&mut self, callbacks: HHCallbacksDispatcher) -> bool {
225 // Register dispatcher
226 if get_dispatchers().lock().unwrap().set::<HHCb>(Arc::new(Mutex::new(callbacks))) {
227 panic!("Tried to set dispatcher for HHCallbacks but it already existed");
228 }
229
230 let callbacks = Box::new(bindings::bthh_callbacks_t {
231 size: 8 * 8,
232 connection_state_cb: Some(connection_state_cb),
233 hid_info_cb: Some(hid_info_cb),
234 protocol_mode_cb: Some(protocol_mode_cb),
235 idle_time_cb: Some(idle_time_cb),
236 get_report_cb: Some(get_report_cb),
237 virtual_unplug_cb: Some(virtual_unplug_cb),
238 handshake_cb: Some(handshake_cb),
239 });
240
241 self.callbacks = Some(callbacks);
242
243 true
244 }
245
246 #[log_args]
247 #[profile_enabled_or(BtStatus::NotReady)]
connect( &self, addr: &mut RawAddress, address_type: BtAddrType, transport: BtTransport, ) -> BtStatus248 pub fn connect(
249 &self,
250 addr: &mut RawAddress,
251 address_type: BtAddrType,
252 transport: BtTransport,
253 ) -> BtStatus {
254 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
255 BtStatus::from(ccall!(
256 self,
257 connect,
258 addr_ptr.into(),
259 address_type.into(),
260 transport.into()
261 ))
262 }
263
264 #[log_args]
265 #[profile_enabled_or(BtStatus::NotReady)]
disconnect( &self, addr: &mut RawAddress, address_type: BtAddrType, transport: BtTransport, reconnect_allowed: bool, ) -> BtStatus266 pub fn disconnect(
267 &self,
268 addr: &mut RawAddress,
269 address_type: BtAddrType,
270 transport: BtTransport,
271 reconnect_allowed: bool,
272 ) -> BtStatus {
273 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
274 BtStatus::from(ccall!(
275 self,
276 disconnect,
277 addr_ptr.into(),
278 address_type.into(),
279 transport.into(),
280 reconnect_allowed
281 ))
282 }
283
284 #[log_args]
285 #[profile_enabled_or(BtStatus::NotReady)]
virtual_unplug( &self, addr: &mut RawAddress, address_type: BtAddrType, transport: BtTransport, ) -> BtStatus286 pub fn virtual_unplug(
287 &self,
288 addr: &mut RawAddress,
289 address_type: BtAddrType,
290 transport: BtTransport,
291 ) -> BtStatus {
292 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
293 BtStatus::from(ccall!(
294 self,
295 virtual_unplug,
296 addr_ptr.into(),
297 address_type.into(),
298 transport.into()
299 ))
300 }
301
302 #[log_args]
303 #[profile_enabled_or(BtStatus::NotReady)]
set_info( &self, addr: &mut RawAddress, address_type: BtAddrType, transport: BtTransport, info: BthhHidInfo, ) -> BtStatus304 pub fn set_info(
305 &self,
306 addr: &mut RawAddress,
307 address_type: BtAddrType,
308 transport: BtTransport,
309 info: BthhHidInfo,
310 ) -> BtStatus {
311 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
312 BtStatus::from(ccall!(
313 self,
314 set_info,
315 addr_ptr.into(),
316 address_type.into(),
317 transport.into(),
318 info
319 ))
320 }
321
322 #[log_args]
323 #[profile_enabled_or(BtStatus::NotReady)]
get_protocol( &self, addr: &mut RawAddress, address_type: BtAddrType, transport: BtTransport, mode: BthhProtocolMode, ) -> BtStatus324 pub fn get_protocol(
325 &self,
326 addr: &mut RawAddress,
327 address_type: BtAddrType,
328 transport: BtTransport,
329 mode: BthhProtocolMode,
330 ) -> BtStatus {
331 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
332 BtStatus::from(ccall!(
333 self,
334 get_protocol,
335 addr_ptr.into(),
336 address_type.into(),
337 transport.into(),
338 bindings::bthh_protocol_mode_t::from(mode)
339 ))
340 }
341
342 #[log_args]
343 #[profile_enabled_or(BtStatus::NotReady)]
set_protocol( &self, addr: &mut RawAddress, address_type: BtAddrType, transport: BtTransport, mode: BthhProtocolMode, ) -> BtStatus344 pub fn set_protocol(
345 &self,
346 addr: &mut RawAddress,
347 address_type: BtAddrType,
348 transport: BtTransport,
349 mode: BthhProtocolMode,
350 ) -> BtStatus {
351 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
352 BtStatus::from(ccall!(
353 self,
354 set_protocol,
355 addr_ptr.into(),
356 address_type.into(),
357 transport.into(),
358 bindings::bthh_protocol_mode_t::from(mode)
359 ))
360 }
361
362 #[log_args]
363 #[profile_enabled_or(BtStatus::NotReady)]
get_idle_time( &self, addr: &mut RawAddress, address_type: BtAddrType, transport: BtTransport, ) -> BtStatus364 pub fn get_idle_time(
365 &self,
366 addr: &mut RawAddress,
367 address_type: BtAddrType,
368 transport: BtTransport,
369 ) -> BtStatus {
370 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
371 BtStatus::from(ccall!(
372 self,
373 get_idle_time,
374 addr_ptr.into(),
375 address_type.into(),
376 transport.into()
377 ))
378 }
379
380 #[log_args]
381 #[profile_enabled_or(BtStatus::NotReady)]
set_idle_time( &self, addr: &mut RawAddress, address_type: BtAddrType, transport: BtTransport, idle_time: u8, ) -> BtStatus382 pub fn set_idle_time(
383 &self,
384 addr: &mut RawAddress,
385 address_type: BtAddrType,
386 transport: BtTransport,
387 idle_time: u8,
388 ) -> BtStatus {
389 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
390 BtStatus::from(ccall!(
391 self,
392 set_idle_time,
393 addr_ptr.into(),
394 address_type.into(),
395 transport.into(),
396 idle_time
397 ))
398 }
399
400 #[log_args]
401 #[profile_enabled_or(BtStatus::NotReady)]
get_report( &self, addr: &mut RawAddress, address_type: BtAddrType, transport: BtTransport, report_type: BthhReportType, report_id: u8, buffer_size: i32, ) -> BtStatus402 pub fn get_report(
403 &self,
404 addr: &mut RawAddress,
405 address_type: BtAddrType,
406 transport: BtTransport,
407 report_type: BthhReportType,
408 report_id: u8,
409 buffer_size: i32,
410 ) -> BtStatus {
411 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
412 BtStatus::from(ccall!(
413 self,
414 get_report,
415 addr_ptr.into(),
416 address_type.into(),
417 transport.into(),
418 bindings::bthh_report_type_t::from(report_type),
419 report_id,
420 buffer_size
421 ))
422 }
423
424 #[log_args]
425 #[profile_enabled_or(BtStatus::NotReady)]
set_report( &self, addr: &mut RawAddress, address_type: BtAddrType, transport: BtTransport, report_type: BthhReportType, report: &mut [u8], ) -> BtStatus426 pub fn set_report(
427 &self,
428 addr: &mut RawAddress,
429 address_type: BtAddrType,
430 transport: BtTransport,
431 report_type: BthhReportType,
432 report: &mut [u8],
433 ) -> BtStatus {
434 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
435 let report_ptr = LTCheckedPtrMut::from(report);
436 BtStatus::from(ccall!(
437 self,
438 set_report,
439 addr_ptr.into(),
440 address_type.into(),
441 transport.into(),
442 bindings::bthh_report_type_t::from(report_type),
443 report_ptr.cast_into::<std::os::raw::c_char>()
444 ))
445 }
446
447 #[log_args]
448 #[profile_enabled_or(BtStatus::NotReady)]
send_data( &mut self, addr: &mut RawAddress, address_type: BtAddrType, transport: BtTransport, data: &mut [u8], ) -> BtStatus449 pub fn send_data(
450 &mut self,
451 addr: &mut RawAddress,
452 address_type: BtAddrType,
453 transport: BtTransport,
454 data: &mut [u8],
455 ) -> BtStatus {
456 let addr_ptr = LTCheckedPtrMut::from_ref(addr);
457 let data_ptr = LTCheckedPtrMut::from(data);
458 BtStatus::from(ccall!(
459 self,
460 send_data,
461 addr_ptr.into(),
462 address_type.into(),
463 transport.into(),
464 data_ptr.cast_into::<std::os::raw::c_char>()
465 ))
466 }
467
468 /// return true if we need to restart hh
469 #[log_args]
configure_enabled_profiles(&mut self) -> bool470 pub fn configure_enabled_profiles(&mut self) -> bool {
471 let needs_restart = self.is_profile_updated;
472 if self.is_profile_updated {
473 ccall!(
474 self,
475 configure_enabled_profiles,
476 self.is_hidp_activated,
477 self.is_hogp_activated
478 );
479 self.is_profile_updated = false;
480 }
481 needs_restart
482 }
483
484 #[log_args]
activate_hogp(&mut self, active: bool)485 pub fn activate_hogp(&mut self, active: bool) {
486 if self.is_hogp_activated != active {
487 self.is_hogp_activated = active;
488 self.is_profile_updated = true;
489 }
490 }
491
492 #[log_args]
activate_hidp(&mut self, active: bool)493 pub fn activate_hidp(&mut self, active: bool) {
494 if self.is_hidp_activated != active {
495 self.is_hidp_activated = active;
496 self.is_profile_updated = true;
497 }
498 }
499
500 #[log_args]
501 #[profile_enabled_or]
cleanup(&mut self)502 pub fn cleanup(&mut self) {
503 ccall!(self, cleanup)
504 }
505 }
506