14aed0296SPaolo Bonzini // Copyright 2024, Linaro Limited
24aed0296SPaolo Bonzini // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
34aed0296SPaolo Bonzini // SPDX-License-Identifier: GPL-2.0-or-later
44aed0296SPaolo Bonzini
54aed0296SPaolo Bonzini //! Bindings to create devices and access device functionality from Rust.
64aed0296SPaolo Bonzini
7201ef001SPaolo Bonzini use std::{
8201ef001SPaolo Bonzini ffi::{CStr, CString},
99a96d410SZhao Liu os::raw::{c_int, c_void},
10201ef001SPaolo Bonzini ptr::NonNull,
11201ef001SPaolo Bonzini };
124aed0296SPaolo Bonzini
13fc22d650SPaolo Bonzini pub use bindings::{ClockEvent, DeviceClass, Property, ResetType};
14716d89f9SPaolo Bonzini
154aed0296SPaolo Bonzini use crate::{
169a96d410SZhao Liu bindings::{self, qdev_init_gpio_in, qdev_init_gpio_out, Error, ResettableClass},
17201ef001SPaolo Bonzini callbacks::FnCall,
18fc22d650SPaolo Bonzini cell::{bql_locked, Opaque},
19a22bd55fSPaolo Bonzini chardev::Chardev,
209a96d410SZhao Liu irq::InterruptSource,
214aed0296SPaolo Bonzini prelude::*,
22d556226dSPaolo Bonzini qom::{ObjectClass, ObjectImpl, Owned},
23716d89f9SPaolo Bonzini vmstate::VMStateDescription,
244aed0296SPaolo Bonzini };
254aed0296SPaolo Bonzini
26fc22d650SPaolo Bonzini /// A safe wrapper around [`bindings::Clock`].
27fc22d650SPaolo Bonzini #[repr(transparent)]
28fc22d650SPaolo Bonzini #[derive(Debug, qemu_api_macros::Wrapper)]
29fc22d650SPaolo Bonzini pub struct Clock(Opaque<bindings::Clock>);
30fc22d650SPaolo Bonzini
31fc22d650SPaolo Bonzini unsafe impl Send for Clock {}
32fc22d650SPaolo Bonzini unsafe impl Sync for Clock {}
33fc22d650SPaolo Bonzini
34fc22d650SPaolo Bonzini /// A safe wrapper around [`bindings::DeviceState`].
35fc22d650SPaolo Bonzini #[repr(transparent)]
36fc22d650SPaolo Bonzini #[derive(Debug, qemu_api_macros::Wrapper)]
37fc22d650SPaolo Bonzini pub struct DeviceState(Opaque<bindings::DeviceState>);
38fc22d650SPaolo Bonzini
39fc22d650SPaolo Bonzini unsafe impl Send for DeviceState {}
40fc22d650SPaolo Bonzini unsafe impl Sync for DeviceState {}
41fc22d650SPaolo Bonzini
425472a38cSPaolo Bonzini /// Trait providing the contents of the `ResettablePhases` struct,
435472a38cSPaolo Bonzini /// which is part of the QOM `Resettable` interface.
445472a38cSPaolo Bonzini pub trait ResettablePhasesImpl {
455472a38cSPaolo Bonzini /// If not None, this is called when the object enters reset. It
465472a38cSPaolo Bonzini /// can reset local state of the object, but it must not do anything that
475472a38cSPaolo Bonzini /// has a side-effect on other objects, such as raising or lowering an
489a96d410SZhao Liu /// [`InterruptSource`], or reading or writing guest memory. It takes the
499a96d410SZhao Liu /// reset's type as argument.
505472a38cSPaolo Bonzini const ENTER: Option<fn(&Self, ResetType)> = None;
515472a38cSPaolo Bonzini
525472a38cSPaolo Bonzini /// If not None, this is called when the object for entry into reset, once
535472a38cSPaolo Bonzini /// every object in the system which is being reset has had its
545472a38cSPaolo Bonzini /// `ResettablePhasesImpl::ENTER` method called. At this point devices
555472a38cSPaolo Bonzini /// can do actions that affect other objects.
565472a38cSPaolo Bonzini ///
575472a38cSPaolo Bonzini /// If in doubt, implement this method.
585472a38cSPaolo Bonzini const HOLD: Option<fn(&Self, ResetType)> = None;
595472a38cSPaolo Bonzini
605472a38cSPaolo Bonzini /// If not None, this phase is called when the object leaves the reset
615472a38cSPaolo Bonzini /// state. Actions affecting other objects are permitted.
625472a38cSPaolo Bonzini const EXIT: Option<fn(&Self, ResetType)> = None;
635472a38cSPaolo Bonzini }
645472a38cSPaolo Bonzini
655472a38cSPaolo Bonzini /// # Safety
665472a38cSPaolo Bonzini ///
675472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
685472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
695472a38cSPaolo Bonzini /// readable/writeable from one thread at any time.
rust_resettable_enter_fn<T: ResettablePhasesImpl>( obj: *mut bindings::Object, typ: ResetType, )705472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>(
717fb4a99dSPaolo Bonzini obj: *mut bindings::Object,
725472a38cSPaolo Bonzini typ: ResetType,
735472a38cSPaolo Bonzini ) {
745472a38cSPaolo Bonzini let state = NonNull::new(obj).unwrap().cast::<T>();
755472a38cSPaolo Bonzini T::ENTER.unwrap()(unsafe { state.as_ref() }, typ);
765472a38cSPaolo Bonzini }
775472a38cSPaolo Bonzini
785472a38cSPaolo Bonzini /// # Safety
795472a38cSPaolo Bonzini ///
805472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
815472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
825472a38cSPaolo Bonzini /// readable/writeable from one thread at any time.
rust_resettable_hold_fn<T: ResettablePhasesImpl>( obj: *mut bindings::Object, typ: ResetType, )835472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>(
847fb4a99dSPaolo Bonzini obj: *mut bindings::Object,
855472a38cSPaolo Bonzini typ: ResetType,
865472a38cSPaolo Bonzini ) {
875472a38cSPaolo Bonzini let state = NonNull::new(obj).unwrap().cast::<T>();
885472a38cSPaolo Bonzini T::HOLD.unwrap()(unsafe { state.as_ref() }, typ);
895472a38cSPaolo Bonzini }
905472a38cSPaolo Bonzini
915472a38cSPaolo Bonzini /// # Safety
925472a38cSPaolo Bonzini ///
935472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
945472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
955472a38cSPaolo Bonzini /// readable/writeable from one thread at any time.
rust_resettable_exit_fn<T: ResettablePhasesImpl>( obj: *mut bindings::Object, typ: ResetType, )965472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_exit_fn<T: ResettablePhasesImpl>(
977fb4a99dSPaolo Bonzini obj: *mut bindings::Object,
985472a38cSPaolo Bonzini typ: ResetType,
995472a38cSPaolo Bonzini ) {
1005472a38cSPaolo Bonzini let state = NonNull::new(obj).unwrap().cast::<T>();
1015472a38cSPaolo Bonzini T::EXIT.unwrap()(unsafe { state.as_ref() }, typ);
1025472a38cSPaolo Bonzini }
1035472a38cSPaolo Bonzini
1044aed0296SPaolo Bonzini /// Trait providing the contents of [`DeviceClass`].
105ac5699c5SPaolo Bonzini pub trait DeviceImpl: ObjectImpl + ResettablePhasesImpl + IsA<DeviceState> {
1064aed0296SPaolo Bonzini /// _Realization_ is the second stage of device creation. It contains
1074aed0296SPaolo Bonzini /// all operations that depend on device properties and can fail (note:
1084aed0296SPaolo Bonzini /// this is not yet supported for Rust devices).
1094aed0296SPaolo Bonzini ///
1104aed0296SPaolo Bonzini /// If not `None`, the parent class's `realize` method is overridden
1114aed0296SPaolo Bonzini /// with the function pointed to by `REALIZE`.
1120f9eb0ffSZhao Liu const REALIZE: Option<fn(&Self)> = None;
1134aed0296SPaolo Bonzini
1144aed0296SPaolo Bonzini /// An array providing the properties that the user can set on the
1154aed0296SPaolo Bonzini /// device. Not a `const` because referencing statics in constants
1164aed0296SPaolo Bonzini /// is unstable until Rust 1.83.0.
properties() -> &'static [Property]1174aed0296SPaolo Bonzini fn properties() -> &'static [Property] {
1184aed0296SPaolo Bonzini &[]
1194aed0296SPaolo Bonzini }
1204aed0296SPaolo Bonzini
1214aed0296SPaolo Bonzini /// A `VMStateDescription` providing the migration format for the device
1224aed0296SPaolo Bonzini /// Not a `const` because referencing statics in constants is unstable
1234aed0296SPaolo Bonzini /// until Rust 1.83.0.
vmsd() -> Option<&'static VMStateDescription>1244aed0296SPaolo Bonzini fn vmsd() -> Option<&'static VMStateDescription> {
1254aed0296SPaolo Bonzini None
1264aed0296SPaolo Bonzini }
1274aed0296SPaolo Bonzini }
1284aed0296SPaolo Bonzini
1294aed0296SPaolo Bonzini /// # Safety
1304aed0296SPaolo Bonzini ///
1314aed0296SPaolo Bonzini /// This function is only called through the QOM machinery and
132d556226dSPaolo Bonzini /// used by `DeviceClass::class_init`.
1334aed0296SPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
1344aed0296SPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
1354aed0296SPaolo Bonzini /// readable/writeable from one thread at any time.
rust_realize_fn<T: DeviceImpl>( dev: *mut bindings::DeviceState, _errp: *mut *mut Error, )136fc22d650SPaolo Bonzini unsafe extern "C" fn rust_realize_fn<T: DeviceImpl>(
137fc22d650SPaolo Bonzini dev: *mut bindings::DeviceState,
138fc22d650SPaolo Bonzini _errp: *mut *mut Error,
139fc22d650SPaolo Bonzini ) {
1407d052039SPaolo Bonzini let state = NonNull::new(dev).unwrap().cast::<T>();
1417d052039SPaolo Bonzini T::REALIZE.unwrap()(unsafe { state.as_ref() });
1424aed0296SPaolo Bonzini }
1434aed0296SPaolo Bonzini
1445472a38cSPaolo Bonzini unsafe impl InterfaceType for ResettableClass {
1455472a38cSPaolo Bonzini const TYPE_NAME: &'static CStr =
1465472a38cSPaolo Bonzini unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_RESETTABLE_INTERFACE) };
1475472a38cSPaolo Bonzini }
1485472a38cSPaolo Bonzini
149d556226dSPaolo Bonzini impl ResettableClass {
150d556226dSPaolo Bonzini /// Fill in the virtual methods of `ResettableClass` based on the
151d556226dSPaolo Bonzini /// definitions in the `ResettablePhasesImpl` trait.
class_init<T: ResettablePhasesImpl>(&mut self)152d556226dSPaolo Bonzini pub fn class_init<T: ResettablePhasesImpl>(&mut self) {
1535472a38cSPaolo Bonzini if <T as ResettablePhasesImpl>::ENTER.is_some() {
154d556226dSPaolo Bonzini self.phases.enter = Some(rust_resettable_enter_fn::<T>);
1555472a38cSPaolo Bonzini }
1565472a38cSPaolo Bonzini if <T as ResettablePhasesImpl>::HOLD.is_some() {
157d556226dSPaolo Bonzini self.phases.hold = Some(rust_resettable_hold_fn::<T>);
1585472a38cSPaolo Bonzini }
1595472a38cSPaolo Bonzini if <T as ResettablePhasesImpl>::EXIT.is_some() {
160d556226dSPaolo Bonzini self.phases.exit = Some(rust_resettable_exit_fn::<T>);
1615472a38cSPaolo Bonzini }
1625472a38cSPaolo Bonzini }
1634aed0296SPaolo Bonzini }
1644aed0296SPaolo Bonzini
165d556226dSPaolo Bonzini impl DeviceClass {
166d556226dSPaolo Bonzini /// Fill in the virtual methods of `DeviceClass` based on the definitions in
167d556226dSPaolo Bonzini /// the `DeviceImpl` trait.
class_init<T: DeviceImpl>(&mut self)168d556226dSPaolo Bonzini pub fn class_init<T: DeviceImpl>(&mut self) {
1694aed0296SPaolo Bonzini if <T as DeviceImpl>::REALIZE.is_some() {
170d556226dSPaolo Bonzini self.realize = Some(rust_realize_fn::<T>);
1714aed0296SPaolo Bonzini }
1724aed0296SPaolo Bonzini if let Some(vmsd) = <T as DeviceImpl>::vmsd() {
173d556226dSPaolo Bonzini self.vmsd = vmsd;
1744aed0296SPaolo Bonzini }
1754aed0296SPaolo Bonzini let prop = <T as DeviceImpl>::properties();
1764aed0296SPaolo Bonzini if !prop.is_empty() {
1774aed0296SPaolo Bonzini unsafe {
178d556226dSPaolo Bonzini bindings::device_class_set_props_n(self, prop.as_ptr(), prop.len());
1794aed0296SPaolo Bonzini }
1804aed0296SPaolo Bonzini }
1814aed0296SPaolo Bonzini
182d556226dSPaolo Bonzini ResettableClass::cast::<DeviceState>(self).class_init::<T>();
183d556226dSPaolo Bonzini self.parent_class.class_init::<T>();
1844aed0296SPaolo Bonzini }
1854aed0296SPaolo Bonzini }
1864aed0296SPaolo Bonzini
1874aed0296SPaolo Bonzini #[macro_export]
1884aed0296SPaolo Bonzini macro_rules! define_property {
1897f2d4181SZhao Liu ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, bit = $bitnr:expr, default = $defval:expr$(,)*) => {
1907f2d4181SZhao Liu $crate::bindings::Property {
1917f2d4181SZhao Liu // use associated function syntax for type checking
1927f2d4181SZhao Liu name: ::std::ffi::CStr::as_ptr($name),
1937f2d4181SZhao Liu info: $prop,
1947f2d4181SZhao Liu offset: $crate::offset_of!($state, $field) as isize,
1957f2d4181SZhao Liu bitnr: $bitnr,
1967f2d4181SZhao Liu set_default: true,
1977f2d4181SZhao Liu defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
1987f2d4181SZhao Liu ..$crate::zeroable::Zeroable::ZERO
1997f2d4181SZhao Liu }
2007f2d4181SZhao Liu };
2014aed0296SPaolo Bonzini ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, default = $defval:expr$(,)*) => {
2024aed0296SPaolo Bonzini $crate::bindings::Property {
2034aed0296SPaolo Bonzini // use associated function syntax for type checking
2044aed0296SPaolo Bonzini name: ::std::ffi::CStr::as_ptr($name),
2054aed0296SPaolo Bonzini info: $prop,
2064aed0296SPaolo Bonzini offset: $crate::offset_of!($state, $field) as isize,
2074aed0296SPaolo Bonzini set_default: true,
2084aed0296SPaolo Bonzini defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
2094aed0296SPaolo Bonzini ..$crate::zeroable::Zeroable::ZERO
2104aed0296SPaolo Bonzini }
2114aed0296SPaolo Bonzini };
2124aed0296SPaolo Bonzini ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty$(,)*) => {
2134aed0296SPaolo Bonzini $crate::bindings::Property {
2144aed0296SPaolo Bonzini // use associated function syntax for type checking
2154aed0296SPaolo Bonzini name: ::std::ffi::CStr::as_ptr($name),
2164aed0296SPaolo Bonzini info: $prop,
2174aed0296SPaolo Bonzini offset: $crate::offset_of!($state, $field) as isize,
2184aed0296SPaolo Bonzini set_default: false,
2194aed0296SPaolo Bonzini ..$crate::zeroable::Zeroable::ZERO
2204aed0296SPaolo Bonzini }
2214aed0296SPaolo Bonzini };
2224aed0296SPaolo Bonzini }
2234aed0296SPaolo Bonzini
2244aed0296SPaolo Bonzini #[macro_export]
2254aed0296SPaolo Bonzini macro_rules! declare_properties {
2264aed0296SPaolo Bonzini ($ident:ident, $($prop:expr),*$(,)*) => {
2274aed0296SPaolo Bonzini pub static $ident: [$crate::bindings::Property; {
2284aed0296SPaolo Bonzini let mut len = 0;
2294aed0296SPaolo Bonzini $({
2304aed0296SPaolo Bonzini _ = stringify!($prop);
2314aed0296SPaolo Bonzini len += 1;
2324aed0296SPaolo Bonzini })*
2334aed0296SPaolo Bonzini len
2344aed0296SPaolo Bonzini }] = [
2354aed0296SPaolo Bonzini $($prop),*,
2364aed0296SPaolo Bonzini ];
2374aed0296SPaolo Bonzini };
2384aed0296SPaolo Bonzini }
2394aed0296SPaolo Bonzini
2404aed0296SPaolo Bonzini unsafe impl ObjectType for DeviceState {
2414aed0296SPaolo Bonzini type Class = DeviceClass;
2424aed0296SPaolo Bonzini const TYPE_NAME: &'static CStr =
2434aed0296SPaolo Bonzini unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_DEVICE) };
2444aed0296SPaolo Bonzini }
245f50cd85cSPaolo Bonzini qom_isa!(DeviceState: Object);
246201ef001SPaolo Bonzini
247201ef001SPaolo Bonzini /// Trait for methods exposed by the [`DeviceState`] class. The methods can be
248201ef001SPaolo Bonzini /// called on all objects that have the trait `IsA<DeviceState>`.
249201ef001SPaolo Bonzini ///
250201ef001SPaolo Bonzini /// The trait should only be used through the blanket implementation,
251201ef001SPaolo Bonzini /// which guarantees safety via `IsA`.
252201ef001SPaolo Bonzini pub trait DeviceMethods: ObjectDeref
253201ef001SPaolo Bonzini where
254201ef001SPaolo Bonzini Self::Target: IsA<DeviceState>,
255201ef001SPaolo Bonzini {
256201ef001SPaolo Bonzini /// Add an input clock named `name`. Invoke the callback with
257201ef001SPaolo Bonzini /// `self` as the first parameter for the events that are requested.
258201ef001SPaolo Bonzini ///
259201ef001SPaolo Bonzini /// The resulting clock is added as a child of `self`, but it also
260201ef001SPaolo Bonzini /// stays alive until after `Drop::drop` is called because C code
261201ef001SPaolo Bonzini /// keeps an extra reference to it until `device_finalize()` calls
262201ef001SPaolo Bonzini /// `qdev_finalize_clocklist()`. Therefore (unlike most cases in
263201ef001SPaolo Bonzini /// which Rust code has a reference to a child object) it would be
264201ef001SPaolo Bonzini /// possible for this function to return a `&Clock` too.
265201ef001SPaolo Bonzini #[inline]
init_clock_in<F: for<'a> FnCall<(&'a Self::Target, ClockEvent)>>( &self, name: &str, _cb: &F, events: ClockEvent, ) -> Owned<Clock>266201ef001SPaolo Bonzini fn init_clock_in<F: for<'a> FnCall<(&'a Self::Target, ClockEvent)>>(
267201ef001SPaolo Bonzini &self,
268201ef001SPaolo Bonzini name: &str,
269201ef001SPaolo Bonzini _cb: &F,
270201ef001SPaolo Bonzini events: ClockEvent,
271201ef001SPaolo Bonzini ) -> Owned<Clock> {
272201ef001SPaolo Bonzini fn do_init_clock_in(
273fc22d650SPaolo Bonzini dev: &DeviceState,
274201ef001SPaolo Bonzini name: &str,
275201ef001SPaolo Bonzini cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)>,
276201ef001SPaolo Bonzini events: ClockEvent,
277201ef001SPaolo Bonzini ) -> Owned<Clock> {
278201ef001SPaolo Bonzini assert!(bql_locked());
279201ef001SPaolo Bonzini
280201ef001SPaolo Bonzini // SAFETY: the clock is heap allocated, but qdev_init_clock_in()
281201ef001SPaolo Bonzini // does not gift the reference to its caller; so use Owned::from to
282201ef001SPaolo Bonzini // add one. The callback is disabled automatically when the clock
283201ef001SPaolo Bonzini // is unparented, which happens before the device is finalized.
284201ef001SPaolo Bonzini unsafe {
285201ef001SPaolo Bonzini let cstr = CString::new(name).unwrap();
286201ef001SPaolo Bonzini let clk = bindings::qdev_init_clock_in(
287fc22d650SPaolo Bonzini dev.as_mut_ptr(),
288201ef001SPaolo Bonzini cstr.as_ptr(),
289201ef001SPaolo Bonzini cb,
290fc22d650SPaolo Bonzini dev.as_void_ptr(),
291201ef001SPaolo Bonzini events.0,
292201ef001SPaolo Bonzini );
293201ef001SPaolo Bonzini
294fc22d650SPaolo Bonzini let clk: &Clock = Clock::from_raw(clk);
295fc22d650SPaolo Bonzini Owned::from(clk)
296201ef001SPaolo Bonzini }
297201ef001SPaolo Bonzini }
298201ef001SPaolo Bonzini
299201ef001SPaolo Bonzini let cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)> = if F::is_some() {
300201ef001SPaolo Bonzini unsafe extern "C" fn rust_clock_cb<T, F: for<'a> FnCall<(&'a T, ClockEvent)>>(
301201ef001SPaolo Bonzini opaque: *mut c_void,
302201ef001SPaolo Bonzini event: ClockEvent,
303201ef001SPaolo Bonzini ) {
304201ef001SPaolo Bonzini // SAFETY: the opaque is "this", which is indeed a pointer to T
305201ef001SPaolo Bonzini F::call((unsafe { &*(opaque.cast::<T>()) }, event))
306201ef001SPaolo Bonzini }
307201ef001SPaolo Bonzini Some(rust_clock_cb::<Self::Target, F>)
308201ef001SPaolo Bonzini } else {
309201ef001SPaolo Bonzini None
310201ef001SPaolo Bonzini };
311201ef001SPaolo Bonzini
312fc22d650SPaolo Bonzini do_init_clock_in(self.upcast(), name, cb, events)
313201ef001SPaolo Bonzini }
314201ef001SPaolo Bonzini
315201ef001SPaolo Bonzini /// Add an output clock named `name`.
316201ef001SPaolo Bonzini ///
317201ef001SPaolo Bonzini /// The resulting clock is added as a child of `self`, but it also
318201ef001SPaolo Bonzini /// stays alive until after `Drop::drop` is called because C code
319201ef001SPaolo Bonzini /// keeps an extra reference to it until `device_finalize()` calls
320201ef001SPaolo Bonzini /// `qdev_finalize_clocklist()`. Therefore (unlike most cases in
321201ef001SPaolo Bonzini /// which Rust code has a reference to a child object) it would be
322201ef001SPaolo Bonzini /// possible for this function to return a `&Clock` too.
323201ef001SPaolo Bonzini #[inline]
init_clock_out(&self, name: &str) -> Owned<Clock>324201ef001SPaolo Bonzini fn init_clock_out(&self, name: &str) -> Owned<Clock> {
325201ef001SPaolo Bonzini unsafe {
326201ef001SPaolo Bonzini let cstr = CString::new(name).unwrap();
327fc22d650SPaolo Bonzini let clk = bindings::qdev_init_clock_out(self.upcast().as_mut_ptr(), cstr.as_ptr());
328201ef001SPaolo Bonzini
329fc22d650SPaolo Bonzini let clk: &Clock = Clock::from_raw(clk);
330fc22d650SPaolo Bonzini Owned::from(clk)
331201ef001SPaolo Bonzini }
332201ef001SPaolo Bonzini }
333a22bd55fSPaolo Bonzini
prop_set_chr(&self, propname: &str, chr: &Owned<Chardev>)334a22bd55fSPaolo Bonzini fn prop_set_chr(&self, propname: &str, chr: &Owned<Chardev>) {
335a22bd55fSPaolo Bonzini assert!(bql_locked());
336a22bd55fSPaolo Bonzini let c_propname = CString::new(propname).unwrap();
337*48627510SPaolo Bonzini let chr: &Chardev = chr;
338a22bd55fSPaolo Bonzini unsafe {
339fc22d650SPaolo Bonzini bindings::qdev_prop_set_chr(
340fc22d650SPaolo Bonzini self.upcast().as_mut_ptr(),
341fc22d650SPaolo Bonzini c_propname.as_ptr(),
342fc22d650SPaolo Bonzini chr.as_mut_ptr(),
343fc22d650SPaolo Bonzini );
344a22bd55fSPaolo Bonzini }
345a22bd55fSPaolo Bonzini }
3469a96d410SZhao Liu
init_gpio_in<F: for<'a> FnCall<(&'a Self::Target, u32, u32)>>( &self, num_lines: u32, _cb: F, )3479a96d410SZhao Liu fn init_gpio_in<F: for<'a> FnCall<(&'a Self::Target, u32, u32)>>(
3489a96d410SZhao Liu &self,
3499a96d410SZhao Liu num_lines: u32,
3509a96d410SZhao Liu _cb: F,
3519a96d410SZhao Liu ) {
352fc22d650SPaolo Bonzini fn do_init_gpio_in(
353fc22d650SPaolo Bonzini dev: &DeviceState,
354fc22d650SPaolo Bonzini num_lines: u32,
355fc22d650SPaolo Bonzini gpio_in_cb: unsafe extern "C" fn(*mut c_void, c_int, c_int),
356fc22d650SPaolo Bonzini ) {
357fc22d650SPaolo Bonzini unsafe {
358fc22d650SPaolo Bonzini qdev_init_gpio_in(dev.as_mut_ptr(), Some(gpio_in_cb), num_lines as c_int);
359fc22d650SPaolo Bonzini }
360fc22d650SPaolo Bonzini }
3619a96d410SZhao Liu
362fc22d650SPaolo Bonzini let _: () = F::ASSERT_IS_SOME;
3639a96d410SZhao Liu unsafe extern "C" fn rust_irq_handler<T, F: for<'a> FnCall<(&'a T, u32, u32)>>(
3649a96d410SZhao Liu opaque: *mut c_void,
3659a96d410SZhao Liu line: c_int,
3669a96d410SZhao Liu level: c_int,
3679a96d410SZhao Liu ) {
3689a96d410SZhao Liu // SAFETY: the opaque was passed as a reference to `T`
3699a96d410SZhao Liu F::call((unsafe { &*(opaque.cast::<T>()) }, line as u32, level as u32))
3709a96d410SZhao Liu }
3719a96d410SZhao Liu
3729a96d410SZhao Liu let gpio_in_cb: unsafe extern "C" fn(*mut c_void, c_int, c_int) =
3739a96d410SZhao Liu rust_irq_handler::<Self::Target, F>;
3749a96d410SZhao Liu
375fc22d650SPaolo Bonzini do_init_gpio_in(self.upcast(), num_lines, gpio_in_cb);
3769a96d410SZhao Liu }
3779a96d410SZhao Liu
init_gpio_out(&self, pins: &[InterruptSource])3789a96d410SZhao Liu fn init_gpio_out(&self, pins: &[InterruptSource]) {
3799a96d410SZhao Liu unsafe {
3809a96d410SZhao Liu qdev_init_gpio_out(
381fc22d650SPaolo Bonzini self.upcast().as_mut_ptr(),
3829a96d410SZhao Liu InterruptSource::slice_as_ptr(pins),
3839a96d410SZhao Liu pins.len() as c_int,
3849a96d410SZhao Liu );
3859a96d410SZhao Liu }
3869a96d410SZhao Liu }
387201ef001SPaolo Bonzini }
388201ef001SPaolo Bonzini
389201ef001SPaolo Bonzini impl<R: ObjectDeref> DeviceMethods for R where R::Target: IsA<DeviceState> {}
390201ef001SPaolo Bonzini
391201ef001SPaolo Bonzini unsafe impl ObjectType for Clock {
392201ef001SPaolo Bonzini type Class = ObjectClass;
393201ef001SPaolo Bonzini const TYPE_NAME: &'static CStr =
394201ef001SPaolo Bonzini unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_CLOCK) };
395201ef001SPaolo Bonzini }
396201ef001SPaolo Bonzini qom_isa!(Clock: Object);
397