diff options
Diffstat (limited to 'rust/kernel/platform.rs')
| -rw-r--r-- | rust/kernel/platform.rs | 178 | 
1 files changed, 177 insertions, 1 deletions
| diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 8f028c76f9fa..7205fe3416d3 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -10,6 +10,7 @@ use crate::{      driver,      error::{from_result, to_result, Result},      io::{mem::IoRequest, Resource}, +    irq::{self, IrqRequest},      of,      prelude::*,      types::Opaque, @@ -284,6 +285,181 @@ impl Device<Bound> {      }  } +macro_rules! define_irq_accessor_by_index { +    ( +        $(#[$meta:meta])* $fn_name:ident, +        $request_fn:ident, +        $reg_type:ident, +        $handler_trait:ident +    ) => { +        $(#[$meta])* +        pub fn $fn_name<'a, T: irq::$handler_trait + 'static>( +            &'a self, +            flags: irq::Flags, +            index: u32, +            name: &'static CStr, +            handler: impl PinInit<T, Error> + 'a, +        ) -> Result<impl PinInit<irq::$reg_type<T>, Error> + 'a> { +            let request = self.$request_fn(index)?; + +            Ok(irq::$reg_type::<T>::new( +                request, +                flags, +                name, +                handler, +            )) +        } +    }; +} + +macro_rules! define_irq_accessor_by_name { +    ( +        $(#[$meta:meta])* $fn_name:ident, +        $request_fn:ident, +        $reg_type:ident, +        $handler_trait:ident +    ) => { +        $(#[$meta])* +        pub fn $fn_name<'a, T: irq::$handler_trait + 'static>( +            &'a self, +            flags: irq::Flags, +            irq_name: &CStr, +            name: &'static CStr, +            handler: impl PinInit<T, Error> + 'a, +        ) -> Result<impl PinInit<irq::$reg_type<T>, Error> + 'a> { +            let request = self.$request_fn(irq_name)?; + +            Ok(irq::$reg_type::<T>::new( +                request, +                flags, +                name, +                handler, +            )) +        } +    }; +} + +impl Device<Bound> { +    /// Returns an [`IrqRequest`] for the IRQ at the given index, if any. +    pub fn irq_by_index(&self, index: u32) -> Result<IrqRequest<'_>> { +        // SAFETY: `self.as_raw` returns a valid pointer to a `struct platform_device`. +        let irq = unsafe { bindings::platform_get_irq(self.as_raw(), index) }; + +        if irq < 0 { +            return Err(Error::from_errno(irq)); +        } + +        // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`. +        Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) }) +    } + +    /// Returns an [`IrqRequest`] for the IRQ at the given index, but does not +    /// print an error if the IRQ cannot be obtained. +    pub fn optional_irq_by_index(&self, index: u32) -> Result<IrqRequest<'_>> { +        // SAFETY: `self.as_raw` returns a valid pointer to a `struct platform_device`. +        let irq = unsafe { bindings::platform_get_irq_optional(self.as_raw(), index) }; + +        if irq < 0 { +            return Err(Error::from_errno(irq)); +        } + +        // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`. +        Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) }) +    } + +    /// Returns an [`IrqRequest`] for the IRQ with the given name, if any. +    pub fn irq_by_name(&self, name: &CStr) -> Result<IrqRequest<'_>> { +        // SAFETY: `self.as_raw` returns a valid pointer to a `struct platform_device`. +        let irq = unsafe { bindings::platform_get_irq_byname(self.as_raw(), name.as_char_ptr()) }; + +        if irq < 0 { +            return Err(Error::from_errno(irq)); +        } + +        // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`. +        Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) }) +    } + +    /// Returns an [`IrqRequest`] for the IRQ with the given name, but does not +    /// print an error if the IRQ cannot be obtained. +    pub fn optional_irq_by_name(&self, name: &CStr) -> Result<IrqRequest<'_>> { +        // SAFETY: `self.as_raw` returns a valid pointer to a `struct platform_device`. +        let irq = unsafe { +            bindings::platform_get_irq_byname_optional(self.as_raw(), name.as_char_ptr()) +        }; + +        if irq < 0 { +            return Err(Error::from_errno(irq)); +        } + +        // SAFETY: `irq` is guaranteed to be a valid IRQ number for `&self`. +        Ok(unsafe { IrqRequest::new(self.as_ref(), irq as u32) }) +    } + +    define_irq_accessor_by_index!( +        /// Returns a [`irq::Registration`] for the IRQ at the given index. +        request_irq_by_index, +        irq_by_index, +        Registration, +        Handler +    ); +    define_irq_accessor_by_name!( +        /// Returns a [`irq::Registration`] for the IRQ with the given name. +        request_irq_by_name, +        irq_by_name, +        Registration, +        Handler +    ); +    define_irq_accessor_by_index!( +        /// Does the same as [`Self::request_irq_by_index`], except that it does +        /// not print an error message if the IRQ cannot be obtained. +        request_optional_irq_by_index, +        optional_irq_by_index, +        Registration, +        Handler +    ); +    define_irq_accessor_by_name!( +        /// Does the same as [`Self::request_irq_by_name`], except that it does +        /// not print an error message if the IRQ cannot be obtained. +        request_optional_irq_by_name, +        optional_irq_by_name, +        Registration, +        Handler +    ); + +    define_irq_accessor_by_index!( +        /// Returns a [`irq::ThreadedRegistration`] for the IRQ at the given index. +        request_threaded_irq_by_index, +        irq_by_index, +        ThreadedRegistration, +        ThreadedHandler +    ); +    define_irq_accessor_by_name!( +        /// Returns a [`irq::ThreadedRegistration`] for the IRQ with the given name. +        request_threaded_irq_by_name, +        irq_by_name, +        ThreadedRegistration, +        ThreadedHandler +    ); +    define_irq_accessor_by_index!( +        /// Does the same as [`Self::request_threaded_irq_by_index`], except +        /// that it does not print an error message if the IRQ cannot be +        /// obtained. +        request_optional_threaded_irq_by_index, +        optional_irq_by_index, +        ThreadedRegistration, +        ThreadedHandler +    ); +    define_irq_accessor_by_name!( +        /// Does the same as [`Self::request_threaded_irq_by_name`], except that +        /// it does not print an error message if the IRQ cannot be obtained. +        request_optional_threaded_irq_by_name, +        optional_irq_by_name, +        ThreadedRegistration, +        ThreadedHandler +    ); +} +  // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic  // argument.  kernel::impl_device_context_deref!(unsafe { Device }); @@ -292,7 +468,7 @@ kernel::impl_device_context_into_aref!(Device);  impl crate::dma::Device for Device<device::Core> {}  // SAFETY: Instances of `Device` are always reference-counted. -unsafe impl crate::types::AlwaysRefCounted for Device { +unsafe impl crate::sync::aref::AlwaysRefCounted for Device {      fn inc_ref(&self) {          // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.          unsafe { bindings::get_device(self.as_ref().as_raw()) }; | 
