1use crate::{
2 ConfigFeatures, EventProviderFeatures, InputAbsInfo, InputBackendError, InputDeviceIds,
3 InputEvent, InputEventsImpl, InputQueryConfig, header,
4};
5use log::{error, warn};
6use static_assertions::assert_not_impl_any;
7use std::ffi::c_void;
8use std::marker::PhantomData;
9use std::os::fd::BorrowedFd;
10use std::ptr::{null, null_mut};
11
12#[macro_export]
13macro_rules! into_rust_result {
14 ($expr:expr) => {
15 into_rust_result!($expr,
16 0 => Ok(()),
17 code @ 0.. => {
18 log::warn!("{}: Unknown OK result code: {code}", stringify!($expr));
19 Ok(())
20 }
21 )
22 };
23 ($expr:expr, $($pat:pat $(if $pat_guard:expr)? => $pat_expr:expr),+ ) => {
24 match $expr {
25 $($pat $(if $pat_guard)? => $pat_expr,)+
26 -1 => Err(InputBackendError::InternalError),
27 -2 => Err(InputBackendError::Again),
28 -3 => Err(InputBackendError::MethodNotSupported),
29 -4 => Err(InputBackendError::InvalidParam),
30 code @ i32::MIN.. => {
31 log::warn!("{}: Unknown error result code: {code}", stringify!($expr));
32 Err(InputBackendError::InternalError)
33 }
34 }
35 };
36}
37
38macro_rules! method_call {
39 ($self:ident.$method:ident($($args:expr),*) ) => {
40 unsafe {
41 $self.vtable.$method
42 .ok_or(InputBackendError::MethodNotSupported)?( $self.instance, $($args),* )
43 }
44 };
45}
46
47pub struct InputEventProviderInstance {
48 instance: *mut c_void,
49 vtable: header::krun_input_event_provider_vtable,
50}
51impl InputEventsImpl for InputEventProviderInstance {
52 fn get_read_notify_fd(&self) -> Result<BorrowedFd<'_>, InputBackendError> {
54 let fd = method_call! {
55 self.get_ready_efd()
56 };
57
58 into_rust_result!(fd,
59 fd if fd >= 0 => Ok(
60 unsafe { BorrowedFd::borrow_raw(fd) }
63 )
64 )
65 }
66
67 fn next_event(&mut self) -> Result<Option<InputEvent>, InputBackendError> {
69 let mut event = InputEvent {
70 type_: 0,
71 code: 0,
72 value: 0,
73 };
74
75 let result = method_call! {
76 self.next_event(&raw mut event)
77 };
78
79 into_rust_result!(result,
80 1 => Ok(Some(event)),
81 0 => Ok(None)
82 )
83 }
84}
85
86pub struct InputConfigInstance {
87 instance: *mut c_void,
88 vtable: header::krun_input_config_vtable,
89}
90
91unsafe impl Send for InputConfigInstance {}
92unsafe impl Sync for InputConfigInstance {}
93
94assert_not_impl_any!(InputEventProviderInstance: Sync, Send);
95
96impl Drop for InputEventProviderInstance {
97 fn drop(&mut self) {
98 let Some(destroy_fn) = self.vtable.destroy else {
99 return;
100 };
101
102 if let Err(e) = into_rust_result!(unsafe { destroy_fn(self.instance) }) {
103 error!("Failed to destroy krun input events instance: {e}");
104 }
105 }
106}
107
108impl Drop for InputConfigInstance {
109 fn drop(&mut self) {
110 let Some(destroy_fn) = self.vtable.destroy else {
111 return;
112 };
113
114 if let Err(e) = into_rust_result!(unsafe { destroy_fn(self.instance) }) {
115 error!("Failed to destroy krun input config instance: {e}");
116 }
117 }
118}
119
120impl InputQueryConfig for InputConfigInstance {
123 fn query_device_name(&self, name_buf: &mut [u8]) -> Result<u8, InputBackendError> {
124 let result = method_call! {
125 self.query_device_name(name_buf.as_mut_ptr(), name_buf.len())
126 };
127
128 into_rust_result!(result,
129 len if len >= 0 => Ok(len as u8)
130 )
131 }
132
133 fn query_serial_name(&self, name_buf: &mut [u8]) -> Result<u8, InputBackendError> {
134 let result = method_call! {
135 self.query_serial_name(name_buf.as_mut_ptr(), name_buf.len())
136 };
137
138 into_rust_result!(result,
139 len if len >= 0 => Ok(len as u8)
140 )
141 }
142
143 fn query_device_ids(&self, ids: &mut InputDeviceIds) -> Result<(), InputBackendError> {
144 let result = method_call! {
145 self.query_device_ids(ids as *mut InputDeviceIds)
146 };
147
148 into_rust_result!(result)
149 }
150
151 fn query_event_capabilities(
152 &self,
153 event_type: u8,
154 bitmap_buf: &mut [u8],
155 ) -> Result<u8, InputBackendError> {
156 let result = method_call! {
157 self.query_event_capabilities(event_type, bitmap_buf.as_mut_ptr(), bitmap_buf.len())
158 };
159
160 into_rust_result!(result,
161 len if len >= 0 => Ok(len as u8)
162 )
163 }
164
165 fn query_abs_info(
166 &self,
167 abs_axis: u8,
168 abs_info: &mut InputAbsInfo,
169 ) -> Result<(), InputBackendError> {
170 let result = method_call! {
171 self.query_abs_info(abs_axis, abs_info as *mut InputAbsInfo)
172 };
173
174 into_rust_result!(result)
175 }
176
177 fn query_properties(&self, properties: &mut [u8]) -> Result<u8, InputBackendError> {
178 let result = method_call! {
179 self.query_properties(properties.as_mut_ptr(), properties.len())
180 };
181
182 into_rust_result!(result,
183 len if len >= 0 => Ok(len as u8)
184 )
185 }
186}
187
188#[derive(Copy, Clone)]
189#[repr(C)]
190pub struct InputConfigBackend<'userdata> {
191 pub features: u64,
192 pub create_userdata: *const c_void,
193 pub create_userdata_lifetime: PhantomData<&'userdata c_void>,
194 pub create_fn: header::krun_input_create_fn,
195 pub vtable: header::krun_input_config_vtable,
196}
197unsafe impl Send for InputConfigBackend<'_> {}
198unsafe impl Sync for InputConfigBackend<'_> {}
199
200impl InputConfigBackend<'_> {
201 pub fn create_instance(&self) -> Result<InputConfigInstance, InputBackendError> {
203 let mut instance = null_mut();
204 if let Some(create_fn) = self.create_fn {
205 into_rust_result!(unsafe {
206 create_fn(&raw mut instance, self.create_userdata, null())
207 })?;
208 }
209 assert!(self.verify());
210
211 Ok(InputConfigInstance {
212 instance,
213 vtable: self.vtable,
214 })
215 }
216
217 pub fn verify(&self) -> bool {
218 let features = ConfigFeatures::from_bits_retain(self.features);
219
220 if !features.contains(ConfigFeatures::QUERY) {
222 error!("This version of libkrun requires QUEUE feature");
223 return false;
224 }
225
226 for feature in features {
227 if feature.contains(ConfigFeatures::QUERY) {
228 if self.vtable.query_device_name.is_none()
229 || self.vtable.query_serial_name.is_none()
230 || self.vtable.query_device_ids.is_none()
231 || self.vtable.query_event_capabilities.is_none()
232 || self.vtable.query_abs_info.is_none()
233 || self.vtable.query_properties.is_none()
234 {
235 error!("Missing required methods for QUERY feature");
236 return false;
237 }
238 } else {
239 warn!("Unknown features ({feature:x}) will be ignored")
240 }
241 }
242 true
243 }
244}
245
246#[derive(Copy, Clone)]
247#[repr(C)]
248pub struct InputEventProviderBackend<'userdata> {
249 pub features: u64,
250 pub create_userdata: *const c_void,
251 pub create_userdata_lifetime: PhantomData<&'userdata c_void>,
252 pub create_fn: header::krun_input_create_fn,
253 pub vtable: header::krun_input_event_provider_vtable,
254}
255
256unsafe impl Send for InputEventProviderBackend<'_> {}
257unsafe impl Sync for InputEventProviderBackend<'_> {}
258
259impl InputEventProviderBackend<'_> {
260 pub fn create_instance(&self) -> Result<InputEventProviderInstance, InputBackendError> {
262 let mut instance = null_mut();
263 if let Some(create_fn) = self.create_fn {
264 into_rust_result!(unsafe {
265 create_fn(&raw mut instance, self.create_userdata, null())
266 })?;
267 }
268 assert!(self.verify());
269
270 Ok(InputEventProviderInstance {
271 instance,
272 vtable: self.vtable,
273 })
274 }
275
276 pub fn verify(&self) -> bool {
277 let features = EventProviderFeatures::from_bits_retain(self.features);
278
279 if !features.contains(EventProviderFeatures::QUEUE) {
281 error!("This version of libkrun requires QUEUE feature");
282 return false;
283 }
284
285 for feature in features {
286 if feature.contains(EventProviderFeatures::QUEUE) {
287 if self.vtable.get_ready_efd.is_none() || self.vtable.get_ready_efd.is_none() {
288 error!("Missing required methods for BASIC_FRAMEBUFFER");
289 return false;
290 }
291 } else {
292 warn!("Unknown features ({feature:x}) will be ignored")
293 }
294 }
295 true
296 }
297}