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