• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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