// SPDX-License-Identifier: GPL-2.012//! Abstractions for [system3//! resources](https://docs.kernel.org/core-api/kernel-api.html#resources-management).4//!5//! C header: [`include/linux/ioport.h`](srctree/include/linux/ioport.h)67use core::{8ops::Deref,9ptr::NonNull, //10};1112use crate::{13prelude::*,14str::CString,15types::Opaque, //16};1718pub use super::{19PhysAddr,20ResourceSize, //21};2223/// A region allocated from a parent [`Resource`].24///25/// # Invariants26///27/// - `self.0` points to a valid `bindings::resource` that was obtained through28/// `bindings::__request_region`.29pub struct Region {30/// The resource returned when the region was requested.31resource: NonNull<bindings::resource>,32/// The name that was passed in when the region was requested. We need to33/// store it for ownership reasons.34_name: CString,35}3637impl Deref for Region {38type Target = Resource;3940fn deref(&self) -> &Self::Target {41// SAFETY: Safe as per the invariant of `Region`.42unsafe { Resource::from_raw(self.resource.as_ptr()) }43}44}4546impl Drop for Region {47fn drop(&mut self) {48let (flags, start, size) = {49let res = &**self;50(res.flags(), res.start(), res.size())51};5253let release_fn = if flags.contains(Flags::IORESOURCE_MEM) {54bindings::release_mem_region55} else {56bindings::release_region57};5859// SAFETY: Safe as per the invariant of `Region`.60unsafe { release_fn(start, size) };61}62}6364// SAFETY: `Region` only holds a pointer to a C `struct resource`, which is safe to be used from65// any thread.66unsafe impl Send for Region {}6768// SAFETY: `Region` only holds a pointer to a C `struct resource`, references to which are69// safe to be used from any thread.70unsafe impl Sync for Region {}7172/// A resource abstraction.73///74/// # Invariants75///76/// [`Resource`] is a transparent wrapper around a valid `bindings::resource`.77#[repr(transparent)]78pub struct Resource(Opaque<bindings::resource>);7980impl Resource {81/// Creates a reference to a [`Resource`] from a valid pointer.82///83/// # Safety84///85/// The caller must ensure that for the duration of 'a, the pointer will86/// point at a valid `bindings::resource`.87///88/// The caller must also ensure that the [`Resource`] is only accessed via the89/// returned reference for the duration of 'a.90pub(crate) const unsafe fn from_raw<'a>(ptr: *mut bindings::resource) -> &'a Self {91// SAFETY: Self is a transparent wrapper around `Opaque<bindings::resource>`.92unsafe { &*ptr.cast() }93}9495/// Requests a resource region.96///97/// Exclusive access will be given and the region will be marked as busy.98/// Further calls to [`Self::request_region`] will return [`None`] if99/// the region, or a part of it, is already in use.100pub fn request_region(101&self,102start: PhysAddr,103size: ResourceSize,104name: CString,105flags: Flags,106) -> Option<Region> {107// SAFETY:108// - Safe as per the invariant of `Resource`.109// - `__request_region` will store a reference to the name, but that is110// safe as we own it and it will not be dropped until the `Region` is111// dropped.112let region = unsafe {113bindings::__request_region(114self.0.get(),115start,116size,117name.as_char_ptr(),118flags.0 as c_int,119)120};121122Some(Region {123resource: NonNull::new(region)?,124_name: name,125})126}127128/// Returns the size of the resource.129pub fn size(&self) -> ResourceSize {130let inner = self.0.get();131// SAFETY: Safe as per the invariants of `Resource`.132unsafe { bindings::resource_size(inner) }133}134135/// Returns the start address of the resource.136pub fn start(&self) -> PhysAddr {137let inner = self.0.get();138// SAFETY: Safe as per the invariants of `Resource`.139unsafe { (*inner).start }140}141142/// Returns the name of the resource.143pub fn name(&self) -> Option<&CStr> {144let inner = self.0.get();145146// SAFETY: Safe as per the invariants of `Resource`.147let name = unsafe { (*inner).name };148149if name.is_null() {150return None;151}152153// SAFETY: In the C code, `resource::name` either contains a null154// pointer or points to a valid NUL-terminated C string, and at this155// point we know it is not null, so we can safely convert it to a156// `CStr`.157Some(unsafe { CStr::from_char_ptr(name) })158}159160/// Returns the flags associated with the resource.161pub fn flags(&self) -> Flags {162let inner = self.0.get();163// SAFETY: Safe as per the invariants of `Resource`.164let flags = unsafe { (*inner).flags };165166Flags(flags)167}168}169170// SAFETY: `Resource` only holds a pointer to a C `struct resource`, which is171// safe to be used from any thread.172unsafe impl Send for Resource {}173174// SAFETY: `Resource` only holds a pointer to a C `struct resource`, references175// to which are safe to be used from any thread.176unsafe impl Sync for Resource {}177178/// Resource flags as stored in the C `struct resource::flags` field.179///180/// They can be combined with the operators `|`, `&`, and `!`.181///182/// Values can be used from the associated constants such as183/// [`Flags::IORESOURCE_IO`].184#[derive(Clone, Copy, PartialEq)]185pub struct Flags(c_ulong);186187impl Flags {188/// Check whether `flags` is contained in `self`.189pub fn contains(self, flags: Flags) -> bool {190(self & flags) == flags191}192}193194impl core::ops::BitOr for Flags {195type Output = Self;196fn bitor(self, rhs: Self) -> Self::Output {197Self(self.0 | rhs.0)198}199}200201impl core::ops::BitAnd for Flags {202type Output = Self;203fn bitand(self, rhs: Self) -> Self::Output {204Self(self.0 & rhs.0)205}206}207208impl core::ops::Not for Flags {209type Output = Self;210fn not(self) -> Self::Output {211Self(!self.0)212}213}214215impl Flags {216/// PCI/ISA I/O ports.217pub const IORESOURCE_IO: Flags = Flags::new(bindings::IORESOURCE_IO);218219/// Resource is software muxed.220pub const IORESOURCE_MUXED: Flags = Flags::new(bindings::IORESOURCE_MUXED);221222/// Resource represents a memory region.223pub const IORESOURCE_MEM: Flags = Flags::new(bindings::IORESOURCE_MEM);224225/// Resource represents a memory region that must be ioremaped using `ioremap_np`.226pub const IORESOURCE_MEM_NONPOSTED: Flags = Flags::new(bindings::IORESOURCE_MEM_NONPOSTED);227228// Always inline to optimize out error path of `build_assert`.229#[inline(always)]230const fn new(value: u32) -> Self {231crate::build_assert!(value as u64 <= c_ulong::MAX as u64);232Flags(value as c_ulong)233}234}235236237