15a5110d2SManos Pitsidianakis // Copyright 2024, Linaro Limited 25a5110d2SManos Pitsidianakis // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org> 35a5110d2SManos Pitsidianakis // SPDX-License-Identifier: GPL-2.0-or-later 45a5110d2SManos Pitsidianakis 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 }; 12ce4a144cSPaolo Bonzini 13*fc22d650SPaolo Bonzini pub use bindings::{ClockEvent, DeviceClass, Property, ResetType}; 14716d89f9SPaolo Bonzini 158c80c472SPaolo Bonzini use crate::{ 169a96d410SZhao Liu bindings::{self, qdev_init_gpio_in, qdev_init_gpio_out, Error, ResettableClass}, 17201ef001SPaolo Bonzini callbacks::FnCall, 18*fc22d650SPaolo Bonzini cell::{bql_locked, Opaque}, 19a22bd55fSPaolo Bonzini chardev::Chardev, 209a96d410SZhao Liu irq::InterruptSource, 217bd8e3efSPaolo Bonzini prelude::*, 22d556226dSPaolo Bonzini qom::{ObjectClass, ObjectImpl, Owned}, 23716d89f9SPaolo Bonzini vmstate::VMStateDescription, 248c80c472SPaolo Bonzini }; 258c80c472SPaolo Bonzini 26*fc22d650SPaolo Bonzini /// A safe wrapper around [`bindings::Clock`]. 27*fc22d650SPaolo Bonzini #[repr(transparent)] 28*fc22d650SPaolo Bonzini #[derive(Debug, qemu_api_macros::Wrapper)] 29*fc22d650SPaolo Bonzini pub struct Clock(Opaque<bindings::Clock>); 30*fc22d650SPaolo Bonzini 31*fc22d650SPaolo Bonzini unsafe impl Send for Clock {} 32*fc22d650SPaolo Bonzini unsafe impl Sync for Clock {} 33*fc22d650SPaolo Bonzini 34*fc22d650SPaolo Bonzini /// A safe wrapper around [`bindings::DeviceState`]. 35*fc22d650SPaolo Bonzini #[repr(transparent)] 36*fc22d650SPaolo Bonzini #[derive(Debug, qemu_api_macros::Wrapper)] 37*fc22d650SPaolo Bonzini pub struct DeviceState(Opaque<bindings::DeviceState>); 38*fc22d650SPaolo Bonzini 39*fc22d650SPaolo Bonzini unsafe impl Send for DeviceState {} 40*fc22d650SPaolo Bonzini unsafe impl Sync for DeviceState {} 41*fc22d650SPaolo 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. 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. 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. 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 1048c80c472SPaolo Bonzini /// Trait providing the contents of [`DeviceClass`]. 105ac5699c5SPaolo Bonzini pub trait DeviceImpl: ObjectImpl + ResettablePhasesImpl + IsA<DeviceState> { 1068c80c472SPaolo Bonzini /// _Realization_ is the second stage of device creation. It contains 1078c80c472SPaolo Bonzini /// all operations that depend on device properties and can fail (note: 1088c80c472SPaolo Bonzini /// this is not yet supported for Rust devices). 1098c80c472SPaolo Bonzini /// 1108c80c472SPaolo Bonzini /// If not `None`, the parent class's `realize` method is overridden 1118c80c472SPaolo Bonzini /// with the function pointed to by `REALIZE`. 1120f9eb0ffSZhao Liu const REALIZE: Option<fn(&Self)> = None; 1138c80c472SPaolo Bonzini 1148c80c472SPaolo Bonzini /// An array providing the properties that the user can set on the 1158c80c472SPaolo Bonzini /// device. Not a `const` because referencing statics in constants 1168c80c472SPaolo Bonzini /// is unstable until Rust 1.83.0. 1178c80c472SPaolo Bonzini fn properties() -> &'static [Property] { 1185f997648SRichard Henderson &[] 1198c80c472SPaolo Bonzini } 1208c80c472SPaolo Bonzini 1218c80c472SPaolo Bonzini /// A `VMStateDescription` providing the migration format for the device 1228c80c472SPaolo Bonzini /// Not a `const` because referencing statics in constants is unstable 1238c80c472SPaolo Bonzini /// until Rust 1.83.0. 1248c80c472SPaolo Bonzini fn vmsd() -> Option<&'static VMStateDescription> { 1258c80c472SPaolo Bonzini None 1268c80c472SPaolo Bonzini } 1278c80c472SPaolo Bonzini } 1288c80c472SPaolo Bonzini 1298c80c472SPaolo Bonzini /// # Safety 1308c80c472SPaolo Bonzini /// 131f75fb90fSPaolo Bonzini /// This function is only called through the QOM machinery and 132d556226dSPaolo Bonzini /// used by `DeviceClass::class_init`. 133f75fb90fSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that 134f75fb90fSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is 135f75fb90fSPaolo Bonzini /// readable/writeable from one thread at any time. 136*fc22d650SPaolo Bonzini unsafe extern "C" fn rust_realize_fn<T: DeviceImpl>( 137*fc22d650SPaolo Bonzini dev: *mut bindings::DeviceState, 138*fc22d650SPaolo Bonzini _errp: *mut *mut Error, 139*fc22d650SPaolo Bonzini ) { 1407d052039SPaolo Bonzini let state = NonNull::new(dev).unwrap().cast::<T>(); 1417d052039SPaolo Bonzini T::REALIZE.unwrap()(unsafe { state.as_ref() }); 142f75fb90fSPaolo Bonzini } 143f75fb90fSPaolo 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. 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 } 163f75fb90fSPaolo Bonzini } 164f75fb90fSPaolo Bonzini 165d556226dSPaolo Bonzini impl DeviceClass { 166d556226dSPaolo Bonzini /// Fill in the virtual methods of `DeviceClass` based on the definitions in 167d556226dSPaolo Bonzini /// the `DeviceImpl` trait. 168d556226dSPaolo Bonzini pub fn class_init<T: DeviceImpl>(&mut self) { 169f75fb90fSPaolo Bonzini if <T as DeviceImpl>::REALIZE.is_some() { 170d556226dSPaolo Bonzini self.realize = Some(rust_realize_fn::<T>); 1718c80c472SPaolo Bonzini } 1728c80c472SPaolo Bonzini if let Some(vmsd) = <T as DeviceImpl>::vmsd() { 173d556226dSPaolo Bonzini self.vmsd = vmsd; 1748c80c472SPaolo Bonzini } 1755f997648SRichard Henderson let prop = <T as DeviceImpl>::properties(); 1765f997648SRichard Henderson if !prop.is_empty() { 1776dd818fbSPaolo Bonzini unsafe { 178d556226dSPaolo Bonzini bindings::device_class_set_props_n(self, prop.as_ptr(), prop.len()); 1795f997648SRichard Henderson } 1808c80c472SPaolo Bonzini } 181cb36da9bSPaolo Bonzini 182d556226dSPaolo Bonzini ResettableClass::cast::<DeviceState>(self).class_init::<T>(); 183d556226dSPaolo Bonzini self.parent_class.class_init::<T>(); 1848c80c472SPaolo Bonzini } 1855a5110d2SManos Pitsidianakis } 1865a5110d2SManos Pitsidianakis 1875a5110d2SManos Pitsidianakis #[macro_export] 1885a5110d2SManos Pitsidianakis 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 }; 201a3057c52SJunjie Mao ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, default = $defval:expr$(,)*) => { 2025a5110d2SManos Pitsidianakis $crate::bindings::Property { 20303a573b9SPaolo Bonzini // use associated function syntax for type checking 2049f7d4520SPaolo Bonzini name: ::std::ffi::CStr::as_ptr($name), 2055a5110d2SManos Pitsidianakis info: $prop, 206f3518400SJunjie Mao offset: $crate::offset_of!($state, $field) as isize, 2075a5110d2SManos Pitsidianakis set_default: true, 20803a573b9SPaolo Bonzini defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 }, 2096e50bde1SPaolo Bonzini ..$crate::zeroable::Zeroable::ZERO 2105a5110d2SManos Pitsidianakis } 2115a5110d2SManos Pitsidianakis }; 212a3057c52SJunjie Mao ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty$(,)*) => { 2135a5110d2SManos Pitsidianakis $crate::bindings::Property { 21403a573b9SPaolo Bonzini // use associated function syntax for type checking 2159f7d4520SPaolo Bonzini name: ::std::ffi::CStr::as_ptr($name), 2165a5110d2SManos Pitsidianakis info: $prop, 217f3518400SJunjie Mao offset: $crate::offset_of!($state, $field) as isize, 2185a5110d2SManos Pitsidianakis set_default: false, 2196e50bde1SPaolo Bonzini ..$crate::zeroable::Zeroable::ZERO 2205a5110d2SManos Pitsidianakis } 2215a5110d2SManos Pitsidianakis }; 2225a5110d2SManos Pitsidianakis } 2235a5110d2SManos Pitsidianakis 2245a5110d2SManos Pitsidianakis #[macro_export] 2255a5110d2SManos Pitsidianakis macro_rules! declare_properties { 2265a5110d2SManos Pitsidianakis ($ident:ident, $($prop:expr),*$(,)*) => { 227c92c447fSPaolo Bonzini pub static $ident: [$crate::bindings::Property; { 2285f997648SRichard Henderson let mut len = 0; 2295a5110d2SManos Pitsidianakis $({ 2305a5110d2SManos Pitsidianakis _ = stringify!($prop); 2315a5110d2SManos Pitsidianakis len += 1; 2325a5110d2SManos Pitsidianakis })* 2335a5110d2SManos Pitsidianakis len 234c92c447fSPaolo Bonzini }] = [ 2355a5110d2SManos Pitsidianakis $($prop),*, 236c92c447fSPaolo Bonzini ]; 2375a5110d2SManos Pitsidianakis }; 2385a5110d2SManos Pitsidianakis } 239ce4a144cSPaolo Bonzini 2406dd818fbSPaolo Bonzini unsafe impl ObjectType for DeviceState { 2416dd818fbSPaolo Bonzini type Class = DeviceClass; 2427bd8e3efSPaolo Bonzini const TYPE_NAME: &'static CStr = 243ce4a144cSPaolo Bonzini unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_DEVICE) }; 2447bd8e3efSPaolo 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] 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( 273*fc22d650SPaolo 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( 287*fc22d650SPaolo Bonzini dev.as_mut_ptr(), 288201ef001SPaolo Bonzini cstr.as_ptr(), 289201ef001SPaolo Bonzini cb, 290*fc22d650SPaolo Bonzini dev.as_void_ptr(), 291201ef001SPaolo Bonzini events.0, 292201ef001SPaolo Bonzini ); 293201ef001SPaolo Bonzini 294*fc22d650SPaolo Bonzini let clk: &Clock = Clock::from_raw(clk); 295*fc22d650SPaolo 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 312*fc22d650SPaolo 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] 324201ef001SPaolo Bonzini fn init_clock_out(&self, name: &str) -> Owned<Clock> { 325201ef001SPaolo Bonzini unsafe { 326201ef001SPaolo Bonzini let cstr = CString::new(name).unwrap(); 327*fc22d650SPaolo Bonzini let clk = bindings::qdev_init_clock_out(self.upcast().as_mut_ptr(), cstr.as_ptr()); 328201ef001SPaolo Bonzini 329*fc22d650SPaolo Bonzini let clk: &Clock = Clock::from_raw(clk); 330*fc22d650SPaolo Bonzini Owned::from(clk) 331201ef001SPaolo Bonzini } 332201ef001SPaolo Bonzini } 333a22bd55fSPaolo Bonzini 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(); 337a22bd55fSPaolo Bonzini unsafe { 338*fc22d650SPaolo Bonzini bindings::qdev_prop_set_chr( 339*fc22d650SPaolo Bonzini self.upcast().as_mut_ptr(), 340*fc22d650SPaolo Bonzini c_propname.as_ptr(), 341*fc22d650SPaolo Bonzini chr.as_mut_ptr(), 342*fc22d650SPaolo Bonzini ); 343a22bd55fSPaolo Bonzini } 344a22bd55fSPaolo Bonzini } 3459a96d410SZhao Liu 3469a96d410SZhao Liu fn init_gpio_in<F: for<'a> FnCall<(&'a Self::Target, u32, u32)>>( 3479a96d410SZhao Liu &self, 3489a96d410SZhao Liu num_lines: u32, 3499a96d410SZhao Liu _cb: F, 3509a96d410SZhao Liu ) { 351*fc22d650SPaolo Bonzini fn do_init_gpio_in( 352*fc22d650SPaolo Bonzini dev: &DeviceState, 353*fc22d650SPaolo Bonzini num_lines: u32, 354*fc22d650SPaolo Bonzini gpio_in_cb: unsafe extern "C" fn(*mut c_void, c_int, c_int), 355*fc22d650SPaolo Bonzini ) { 356*fc22d650SPaolo Bonzini unsafe { 357*fc22d650SPaolo Bonzini qdev_init_gpio_in(dev.as_mut_ptr(), Some(gpio_in_cb), num_lines as c_int); 358*fc22d650SPaolo Bonzini } 359*fc22d650SPaolo Bonzini } 3609a96d410SZhao Liu 361*fc22d650SPaolo Bonzini let _: () = F::ASSERT_IS_SOME; 3629a96d410SZhao Liu unsafe extern "C" fn rust_irq_handler<T, F: for<'a> FnCall<(&'a T, u32, u32)>>( 3639a96d410SZhao Liu opaque: *mut c_void, 3649a96d410SZhao Liu line: c_int, 3659a96d410SZhao Liu level: c_int, 3669a96d410SZhao Liu ) { 3679a96d410SZhao Liu // SAFETY: the opaque was passed as a reference to `T` 3689a96d410SZhao Liu F::call((unsafe { &*(opaque.cast::<T>()) }, line as u32, level as u32)) 3699a96d410SZhao Liu } 3709a96d410SZhao Liu 3719a96d410SZhao Liu let gpio_in_cb: unsafe extern "C" fn(*mut c_void, c_int, c_int) = 3729a96d410SZhao Liu rust_irq_handler::<Self::Target, F>; 3739a96d410SZhao Liu 374*fc22d650SPaolo Bonzini do_init_gpio_in(self.upcast(), num_lines, gpio_in_cb); 3759a96d410SZhao Liu } 3769a96d410SZhao Liu 3779a96d410SZhao Liu fn init_gpio_out(&self, pins: &[InterruptSource]) { 3789a96d410SZhao Liu unsafe { 3799a96d410SZhao Liu qdev_init_gpio_out( 380*fc22d650SPaolo Bonzini self.upcast().as_mut_ptr(), 3819a96d410SZhao Liu InterruptSource::slice_as_ptr(pins), 3829a96d410SZhao Liu pins.len() as c_int, 3839a96d410SZhao Liu ); 3849a96d410SZhao Liu } 3859a96d410SZhao Liu } 386201ef001SPaolo Bonzini } 387201ef001SPaolo Bonzini 388201ef001SPaolo Bonzini impl<R: ObjectDeref> DeviceMethods for R where R::Target: IsA<DeviceState> {} 389201ef001SPaolo Bonzini 390201ef001SPaolo Bonzini unsafe impl ObjectType for Clock { 391201ef001SPaolo Bonzini type Class = ObjectClass; 392201ef001SPaolo Bonzini const TYPE_NAME: &'static CStr = 393201ef001SPaolo Bonzini unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_CLOCK) }; 394201ef001SPaolo Bonzini } 395201ef001SPaolo Bonzini qom_isa!(Clock: Object); 396