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