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