Merge "Enum-ify stack/include/smp_api_types::tSMP_KEYS_BITMASK"
diff --git a/gd/rust/topshim/bindings/wrapper.h b/gd/rust/topshim/bindings/wrapper.h
index ba4a1f0..f535180 100644
--- a/gd/rust/topshim/bindings/wrapper.h
+++ b/gd/rust/topshim/bindings/wrapper.h
@@ -1,4 +1,10 @@
#pragma once
+// Base
#include "btcore/include/hal_util.h"
#include "include/hardware/bluetooth.h"
+
+// Profiles
+
+// Hid host profile
+#include "include/hardware/bt_hh.h"
diff --git a/gd/rust/topshim/build.rs b/gd/rust/topshim/build.rs
index b554247..69f0b2d 100644
--- a/gd/rust/topshim/build.rs
+++ b/gd/rust/topshim/build.rs
@@ -34,8 +34,8 @@
.clang_args(libchrome_paths)
.clang_args(clang_args)
.enable_cxx_namespaces()
- .whitelist_type("bt_.*")
- .whitelist_function("bt_.*")
+ .whitelist_type("(bt_|bthh_).*")
+ .whitelist_function("(bt_|bthh_).*")
.whitelist_function("hal_util_.*")
// We must opaque out std:: in order to prevent bindgen from choking
.opaque_type("std::.*")
diff --git a/gd/rust/topshim/src/btif.rs b/gd/rust/topshim/src/btif.rs
index d6e87e8..d9fd8ea 100644
--- a/gd/rust/topshim/src/btif.rs
+++ b/gd/rust/topshim/src/btif.rs
@@ -10,6 +10,8 @@
use std::vec::Vec;
use topshim_macros::cb_variant;
+use crate::profiles::hid_host::HidHost;
+
#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtState {
@@ -233,6 +235,18 @@
pub type BtPinCode = bindings::bt_pin_code_t;
+pub enum SupportedProfiles {
+ HidHost,
+}
+
+impl From<SupportedProfiles> for Vec<u8> {
+ fn from(item: SupportedProfiles) -> Self {
+ match item {
+ HidHost => "hidhost".bytes().collect::<Vec<u8>>(),
+ }
+ }
+}
+
#[cxx::bridge(namespace = bluetooth::topshim::rust)]
mod ffi {
unsafe extern "C++" {
@@ -488,6 +502,14 @@
let cvariant = bindings::bt_ssp_variant_t::from(variant);
ccall!(self, ssp_reply, addr, cvariant, accept, passkey)
}
+
+ pub(crate) fn get_profile_interface(
+ &self,
+ profile: SupportedProfiles,
+ ) -> *const std::os::raw::c_void {
+ let cprofile = Vec::<u8>::from(profile);
+ ccall!(self, get_profile_interface, cprofile.as_slice().as_ptr() as *const i8)
+ }
}
pub fn get_btinterface() -> Option<BluetoothInterface> {
diff --git a/gd/rust/topshim/src/lib.rs b/gd/rust/topshim/src/lib.rs
index 1032dfd..f8f5475 100644
--- a/gd/rust/topshim/src/lib.rs
+++ b/gd/rust/topshim/src/lib.rs
@@ -6,4 +6,5 @@
pub mod bindings;
pub mod btif;
+pub mod profiles;
pub mod topstack;
diff --git a/gd/rust/topshim/src/profiles/hid_host.rs b/gd/rust/topshim/src/profiles/hid_host.rs
new file mode 100644
index 0000000..4320f3f
--- /dev/null
+++ b/gd/rust/topshim/src/profiles/hid_host.rs
@@ -0,0 +1,268 @@
+use crate::bindings::root as bindings;
+use crate::btif::RawAddress;
+use crate::ccall;
+use crate::topstack::get_dispatchers;
+
+use num_traits::cast::{FromPrimitive, ToPrimitive};
+use std::sync::{Arc, Mutex};
+use topshim_macros::cb_variant;
+
+#[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BthhConnectionState {
+ Connected = 0,
+ Connecting,
+ Disconnected,
+ Disconnecting,
+ Unknown = 0xff,
+}
+
+impl From<bindings::bthh_connection_state_t> for BthhConnectionState {
+ fn from(item: bindings::bthh_connection_state_t) -> Self {
+ BthhConnectionState::from_u32(item).unwrap_or_else(|| BthhConnectionState::Unknown)
+ }
+}
+
+#[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BthhStatus {
+ Ok = 0,
+ HsHidNotReady,
+ HsInvalidRptId,
+ HsTransNotSpt,
+ HsInvalidParam,
+ HsError,
+ Error,
+ ErrSdp,
+ ErrProto,
+ ErrDbFull,
+ ErrTodUnspt,
+ ErrNoRes,
+ ErrAuthFailed,
+ ErrHdl,
+
+ Unknown,
+}
+
+impl From<bindings::bthh_status_t> for BthhStatus {
+ fn from(item: bindings::bthh_status_t) -> Self {
+ BthhStatus::from_u32(item).unwrap_or_else(|| BthhStatus::Unknown)
+ }
+}
+
+pub type BthhHidInfo = bindings::bthh_hid_info_t;
+
+#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BthhProtocolMode {
+ ReportMode = 0,
+ BootMode = 1,
+ UnsupportedMode = 0xff,
+}
+
+impl From<bindings::bthh_protocol_mode_t> for BthhProtocolMode {
+ fn from(item: bindings::bthh_protocol_mode_t) -> Self {
+ BthhProtocolMode::from_u32(item).unwrap_or_else(|| BthhProtocolMode::UnsupportedMode)
+ }
+}
+
+impl From<BthhProtocolMode> for bindings::bthh_protocol_mode_t {
+ fn from(item: BthhProtocolMode) -> Self {
+ item.to_u32().unwrap()
+ }
+}
+
+#[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum BthhReportType {
+ InputReport = 1,
+ OutputReport = 2,
+ FeatureReport = 3,
+}
+
+impl From<BthhReportType> for bindings::bthh_report_type_t {
+ fn from(item: BthhReportType) -> Self {
+ item.to_u32().unwrap()
+ }
+}
+
+fn convert_report(count: i32, raw: *mut u8) -> Vec<u8> {
+ let mut v: Vec<u8> = Vec::new();
+ for i in 0..isize::from_i32(count).unwrap() {
+ let p: *const u8 = unsafe { raw.offset(i) };
+ v.push(unsafe { *p });
+ }
+
+ return v;
+}
+
+pub enum HHCallbacks {
+ ConnectionState(RawAddress, BthhConnectionState),
+ VirtualUnplug(RawAddress, BthhStatus),
+ HidInfo(RawAddress, BthhHidInfo),
+ ProtocolMode(RawAddress, BthhStatus, BthhProtocolMode),
+ IdleTime(RawAddress, BthhStatus, i32),
+ GetReport(RawAddress, BthhStatus, Vec<u8>, i32),
+ Handshake(RawAddress, BthhStatus),
+}
+
+pub struct HHCallbacksDispatcher {
+ dispatch: Box<Fn(HHCallbacks) + Send>,
+}
+
+type HHCb = Arc<Mutex<HHCallbacksDispatcher>>;
+
+cb_variant!(HHCb, connection_state_cb -> HHCallbacks::ConnectionState,
+*mut RawAddress, bindings::bthh_connection_state_t -> BthhConnectionState, {
+ let _0 = unsafe {*_0};
+});
+cb_variant!(HHCb, virtual_unplug_cb -> HHCallbacks::VirtualUnplug,
+*mut RawAddress, bindings::bthh_status_t -> BthhStatus, {
+ let _0 = unsafe {*_0};
+});
+cb_variant!(HHCb, hid_info_cb -> HHCallbacks::HidInfo,
+*mut RawAddress, bindings::bthh_hid_info_t -> BthhHidInfo, {
+ let _0 = unsafe {*_0};
+});
+cb_variant!(HHCb, protocol_mode_cb -> HHCallbacks::ProtocolMode,
+*mut RawAddress, bindings::bthh_status_t -> BthhStatus,
+bindings::bthh_protocol_mode_t -> BthhProtocolMode, {
+ let _0 = unsafe {*_0};
+});
+cb_variant!(HHCb, idle_time_cb -> HHCallbacks::IdleTime,
+*mut RawAddress, bindings::bthh_status_t -> BthhStatus, i32, {
+ let _0 = unsafe {*_0};
+});
+cb_variant!(HHCb, get_report_cb -> HHCallbacks::GetReport,
+*mut RawAddress, bindings::bthh_status_t -> BthhStatus, *mut u8, i32, {
+ let _0 = unsafe {*_0};
+ let _2 = convert_report(_3, _2);
+});
+cb_variant!(HHCb, handshake_cb -> HHCallbacks::Handshake,
+*mut RawAddress, bindings::bthh_status_t -> BthhStatus, {
+ let _0 = unsafe{*_0};
+});
+
+struct RawHHWrapper {
+ raw: *const bindings::bthh_interface_t,
+}
+
+// Pointers unsafe due to ownership but this is a static pointer so Send is ok
+unsafe impl Send for RawHHWrapper {}
+
+pub struct HidHost {
+ internal: RawHHWrapper,
+ is_init: bool,
+ // Keep callback object in memory (underlying code doesn't make copy)
+ callbacks: Option<Box<bindings::bthh_callbacks_t>>,
+}
+
+impl HidHost {
+ pub fn is_initialized(&self) -> bool {
+ self.is_init
+ }
+
+ pub fn initialize(&mut self, callbacks: HHCallbacksDispatcher) -> bool {
+ // Register dispatcher
+ if get_dispatchers().lock().unwrap().set::<HHCb>(Arc::new(Mutex::new(callbacks))) {
+ panic!("Tried to set dispatcher for HHCallbacks but it already existed");
+ }
+
+ let mut callbacks = Box::new(bindings::bthh_callbacks_t {
+ size: 8 * 8,
+ connection_state_cb: Some(connection_state_cb),
+ hid_info_cb: Some(hid_info_cb),
+ protocol_mode_cb: Some(protocol_mode_cb),
+ idle_time_cb: Some(idle_time_cb),
+ get_report_cb: Some(get_report_cb),
+ virtual_unplug_cb: Some(virtual_unplug_cb),
+ handshake_cb: Some(handshake_cb),
+ });
+
+ let rawcb = &mut *callbacks;
+
+ let init = ccall!(self, init, rawcb);
+ self.is_init = BthhStatus::from(init) == BthhStatus::Ok;
+ self.callbacks = Some(callbacks);
+
+ return self.is_init;
+ }
+
+ pub fn connect(&self, addr: &mut RawAddress) -> BthhStatus {
+ BthhStatus::from(ccall!(self, connect, addr))
+ }
+
+ pub fn disconnect(&self, addr: &mut RawAddress) -> BthhStatus {
+ BthhStatus::from(ccall!(self, disconnect, addr))
+ }
+
+ pub fn virtual_unplug(&self, addr: &mut RawAddress) -> BthhStatus {
+ BthhStatus::from(ccall!(self, virtual_unplug, addr))
+ }
+
+ pub fn set_info(&self, addr: &mut RawAddress, info: BthhHidInfo) -> BthhStatus {
+ BthhStatus::from(ccall!(self, set_info, addr, info))
+ }
+
+ pub fn get_protocol(&self, addr: &mut RawAddress, mode: BthhProtocolMode) -> BthhStatus {
+ BthhStatus::from(ccall!(
+ self,
+ get_protocol,
+ addr,
+ bindings::bthh_protocol_mode_t::from(mode)
+ ))
+ }
+
+ pub fn set_protocol(&self, addr: &mut RawAddress, mode: BthhProtocolMode) -> BthhStatus {
+ BthhStatus::from(ccall!(
+ self,
+ set_protocol,
+ addr,
+ bindings::bthh_protocol_mode_t::from(mode)
+ ))
+ }
+
+ pub fn get_idle_time(&self, addr: &mut RawAddress) -> BthhStatus {
+ BthhStatus::from(ccall!(self, get_idle_time, addr))
+ }
+
+ pub fn set_idle_time(&self, addr: &mut RawAddress, idle_time: u8) -> BthhStatus {
+ BthhStatus::from(ccall!(self, set_idle_time, addr, idle_time))
+ }
+
+ pub fn get_report(
+ &self,
+ addr: &mut RawAddress,
+ report_type: BthhReportType,
+ report_id: u8,
+ buffer_size: i32,
+ ) -> BthhStatus {
+ BthhStatus::from(ccall!(
+ self,
+ get_report,
+ addr,
+ bindings::bthh_report_type_t::from(report_type),
+ report_id,
+ buffer_size
+ ))
+ }
+
+ pub fn set_report(
+ &self,
+ addr: &mut RawAddress,
+ report_type: BthhReportType,
+ report: &mut [u8],
+ ) -> BthhStatus {
+ BthhStatus::from(ccall!(
+ self,
+ set_report,
+ addr,
+ bindings::bthh_report_type_t::from(report_type),
+ report.as_mut_ptr() as *mut i8
+ ))
+ }
+
+ pub fn cleanup(&self) {
+ ccall!(self, cleanup)
+ }
+}
diff --git a/gd/rust/topshim/src/profiles/mod.rs b/gd/rust/topshim/src/profiles/mod.rs
new file mode 100644
index 0000000..12760a7
--- /dev/null
+++ b/gd/rust/topshim/src/profiles/mod.rs
@@ -0,0 +1 @@
+pub mod hid_host;