mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-27 20:33:54 -06:00
rust: add bindings for gpio_{in|out} initialization
Wrap qdev_init_gpio_{in|out} as methods in DeviceMethods. And for qdev_init_gpio_in, based on FnCall, it can support idiomatic Rust callback without the need for C style wrapper. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> Link: https://lore.kernel.org/r/20250210030051.2562726-5-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
e6f1195f55
commit
9a96d41007
2 changed files with 43 additions and 5 deletions
|
@ -6,17 +6,18 @@
|
|||
|
||||
use std::{
|
||||
ffi::{CStr, CString},
|
||||
os::raw::c_void,
|
||||
os::raw::{c_int, c_void},
|
||||
ptr::NonNull,
|
||||
};
|
||||
|
||||
pub use bindings::{Clock, ClockEvent, DeviceClass, DeviceState, Property, ResetType};
|
||||
|
||||
use crate::{
|
||||
bindings::{self, Error, ResettableClass},
|
||||
bindings::{self, qdev_init_gpio_in, qdev_init_gpio_out, Error, ResettableClass},
|
||||
callbacks::FnCall,
|
||||
cell::bql_locked,
|
||||
chardev::Chardev,
|
||||
irq::InterruptSource,
|
||||
prelude::*,
|
||||
qom::{ClassInitImpl, ObjectClass, ObjectImpl, Owned},
|
||||
vmstate::VMStateDescription,
|
||||
|
@ -28,8 +29,8 @@ pub trait ResettablePhasesImpl {
|
|||
/// If not None, this is called when the object enters reset. It
|
||||
/// can reset local state of the object, but it must not do anything that
|
||||
/// has a side-effect on other objects, such as raising or lowering an
|
||||
/// [`InterruptSource`](crate::irq::InterruptSource), or reading or
|
||||
/// writing guest memory. It takes the reset's type as argument.
|
||||
/// [`InterruptSource`], or reading or writing guest memory. It takes the
|
||||
/// reset's type as argument.
|
||||
const ENTER: Option<fn(&Self, ResetType)> = None;
|
||||
|
||||
/// If not None, this is called when the object for entry into reset, once
|
||||
|
@ -318,6 +319,44 @@ where
|
|||
bindings::qdev_prop_set_chr(self.as_mut_ptr(), c_propname.as_ptr(), chr.as_mut_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
fn init_gpio_in<F: for<'a> FnCall<(&'a Self::Target, u32, u32)>>(
|
||||
&self,
|
||||
num_lines: u32,
|
||||
_cb: F,
|
||||
) {
|
||||
let _: () = F::ASSERT_IS_SOME;
|
||||
|
||||
unsafe extern "C" fn rust_irq_handler<T, F: for<'a> FnCall<(&'a T, u32, u32)>>(
|
||||
opaque: *mut c_void,
|
||||
line: c_int,
|
||||
level: c_int,
|
||||
) {
|
||||
// SAFETY: the opaque was passed as a reference to `T`
|
||||
F::call((unsafe { &*(opaque.cast::<T>()) }, line as u32, level as u32))
|
||||
}
|
||||
|
||||
let gpio_in_cb: unsafe extern "C" fn(*mut c_void, c_int, c_int) =
|
||||
rust_irq_handler::<Self::Target, F>;
|
||||
|
||||
unsafe {
|
||||
qdev_init_gpio_in(
|
||||
self.as_mut_ptr::<DeviceState>(),
|
||||
Some(gpio_in_cb),
|
||||
num_lines as c_int,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn init_gpio_out(&self, pins: &[InterruptSource]) {
|
||||
unsafe {
|
||||
qdev_init_gpio_out(
|
||||
self.as_mut_ptr::<DeviceState>(),
|
||||
InterruptSource::slice_as_ptr(pins),
|
||||
pins.len() as c_int,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: ObjectDeref> DeviceMethods for R where R::Target: IsA<DeviceState> {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue