1 //! This library provides UHID for HFP to interact with WebHID. 2 3 use bt_topshim::topstack; 4 use log::debug; 5 use std::convert::TryFrom; 6 use std::fs::{File, OpenOptions}; 7 use std::io::{self, Read, Write}; 8 use std::os::unix::fs::OpenOptionsExt; 9 use std::path::Path; 10 pub use uhid_virt::OutputEvent; 11 use uhid_virt::{Bus, CreateParams, InputEvent, StreamError, UHID_EVENT_SIZE}; 12 13 pub const BLUETOOTH_TELEPHONY_UHID_REPORT_ID: u8 = 1; 14 pub const UHID_INPUT_NONE: u8 = 0; 15 pub const UHID_INPUT_HOOK_SWITCH: u8 = 1 << 0; 16 pub const UHID_INPUT_PHONE_MUTE: u8 = 1 << 1; 17 pub const UHID_INPUT_DROP: u8 = 1 << 2; 18 pub const UHID_OUTPUT_NONE: u8 = 0; 19 pub const UHID_OUTPUT_RING: u8 = 1 << 0; 20 pub const UHID_OUTPUT_OFF_HOOK: u8 = 1 << 1; 21 pub const UHID_OUTPUT_MUTE: u8 = 1 << 2; 22 23 const RDESC: [u8; 57] = [ 24 0x05, 25 0x0B, // Usage Page (Telephony) 26 0x09, 27 0x05, // Usage (Headset) 28 0xA1, 29 0x01, // Collection (Application) 30 0x85, 31 BLUETOOTH_TELEPHONY_UHID_REPORT_ID, // Report ID (1) 32 0x05, 33 0x0B, // Usage Page (Telephony) 34 0x15, 35 0x00, // Logical Minimum (0) 36 0x25, 37 0x01, // Logical Maximum (1) 38 0x09, 39 0x20, // Usage (Hook Switch) 40 0x09, 41 0x2f, // Usage (Phone Mute) 42 0x09, 43 0x26, // Usage (Drop) 44 0x75, 45 0x01, // Report Size (1) 46 0x95, 47 0x03, // Report Count (3) 48 0x81, 49 // Input (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position, 50 // Non-volatile) 51 0x22, 52 0x75, 53 0x01, // Report Size (1) 54 0x95, 55 0x05, // Report Count (5) 56 0x81, 57 0x01, // Input 58 0x05, 59 0x08, // Usage Page (LEDs) 60 0x15, 61 0x00, // Logical Minimum (0) 62 0x25, 63 0x01, // Logical Maximum (1) 64 0x09, 65 0x18, // Usage (Ring) 66 0x09, 67 0x17, // Usage (Off-Hook) 68 0x09, 69 0x09, // Usage (Mute) 70 0x75, 71 0x01, // Report Size (1) 72 0x95, 73 0x03, // Report Count (3) 74 0x91, 75 // Output (Data,Var,Abs,No Wrap,Linear,No Preferred State, 76 // No Null Position, Non-volatile) 77 0x22, 78 0x75, 79 0x01, // Report Size (1) 80 0x95, 81 0x05, // Report Count (5) 82 0x91, 83 0x01, // Output 84 0xC0, // End Collection 85 ]; 86 87 pub struct UHidHfp { 88 handle: File, 89 } 90 91 impl UHidHfp { create<F>( adapter_addr: String, remote_addr: String, remote_name: String, output_callback: F, ) -> UHidHfp where F: Fn(OutputEvent) + std::marker::Send + 'static,92 pub fn create<F>( 93 adapter_addr: String, 94 remote_addr: String, 95 remote_name: String, 96 output_callback: F, 97 ) -> UHidHfp 98 where 99 F: Fn(OutputEvent) + std::marker::Send + 'static, 100 { 101 let rd_data = RDESC.to_vec(); 102 let create_params = CreateParams { 103 name: remote_name, 104 phys: adapter_addr, 105 uniq: remote_addr.clone(), 106 bus: Bus::BLUETOOTH, 107 vendor: 0, 108 product: 0, 109 version: 0, 110 country: 0, 111 rd_data, 112 }; 113 114 let create_event: [u8; UHID_EVENT_SIZE] = InputEvent::Create(create_params).into(); 115 let mut options = OpenOptions::new(); 116 options.read(true); 117 options.write(true); 118 if cfg!(unix) { 119 options.custom_flags(libc::O_RDWR | libc::O_CLOEXEC); 120 } 121 let mut uhid_writer = options.open(Path::new("/dev/uhid")).unwrap(); 122 let mut uhid_reader = uhid_writer.try_clone().unwrap(); 123 uhid_writer.write_all(&create_event).unwrap(); 124 125 topstack::get_runtime().spawn_blocking(move || { 126 let mut event = [0u8; UHID_EVENT_SIZE]; 127 debug!("UHID: reading loop start"); 128 loop { 129 match uhid_reader.read_exact(&mut event) { 130 Err(e) => { 131 log::error!("UHID: Read error: {:?}", e); 132 break; 133 } 134 Ok(_) => (), 135 } 136 match OutputEvent::try_from(event) { 137 Ok(m) => { 138 match m { 139 OutputEvent::Stop => break, 140 _ => (), 141 }; 142 143 output_callback(m); 144 } 145 Err(e) => { 146 match e { 147 StreamError::Io(e) => log::error!("UHID: IO error: {}", e), 148 StreamError::UnknownEventType(e) => { 149 log::error!("UHID: Unknown event type: {}", e) 150 } 151 } 152 break; 153 } 154 } 155 } 156 debug!("UHID: reading loop completed"); 157 }); 158 159 UHidHfp { handle: uhid_writer } 160 } 161 destroy(&mut self) -> io::Result<()>162 pub fn destroy(&mut self) -> io::Result<()> { 163 let destroy_event: [u8; UHID_EVENT_SIZE] = InputEvent::Destroy.into(); 164 self.handle.write_all(&destroy_event) 165 } 166 send_input(&mut self, report: u8) -> io::Result<()>167 pub fn send_input(&mut self, report: u8) -> io::Result<()> { 168 let data: [u8; 2] = [BLUETOOTH_TELEPHONY_UHID_REPORT_ID, report]; 169 let input_event: [u8; UHID_EVENT_SIZE] = InputEvent::Input { data: &data }.into(); 170 self.handle.write_all(&input_event) 171 } 172 } 173