// 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::ops::Deref;8use core::ptr::NonNull;910use crate::prelude::*;11use crate::str::{CStr, CString};12use crate::types::Opaque;1314/// Resource Size type.15///16/// This is a type alias to either `u32` or `u64` depending on the config option17/// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures.18pub type ResourceSize = bindings::phys_addr_t;1920/// A region allocated from a parent [`Resource`].21///22/// # Invariants23///24/// - `self.0` points to a valid `bindings::resource` that was obtained through25/// `bindings::__request_region`.26pub struct Region {27/// The resource returned when the region was requested.28resource: NonNull<bindings::resource>,29/// The name that was passed in when the region was requested. We need to30/// store it for ownership reasons.31_name: CString,32}3334impl Deref for Region {35type Target = Resource;3637fn deref(&self) -> &Self::Target {38// SAFETY: Safe as per the invariant of `Region`.39unsafe { Resource::from_raw(self.resource.as_ptr()) }40}41}4243impl Drop for Region {44fn drop(&mut self) {45let (flags, start, size) = {46let res = &**self;47(res.flags(), res.start(), res.size())48};4950let release_fn = if flags.contains(Flags::IORESOURCE_MEM) {51bindings::release_mem_region52} else {53bindings::release_region54};5556// SAFETY: Safe as per the invariant of `Region`.57unsafe { release_fn(start, size) };58}59}6061// SAFETY: `Region` only holds a pointer to a C `struct resource`, which is safe to be used from62// any thread.63unsafe impl Send for Region {}6465// SAFETY: `Region` only holds a pointer to a C `struct resource`, references to which are66// safe to be used from any thread.67unsafe impl Sync for Region {}6869/// A resource abstraction.70///71/// # Invariants72///73/// [`Resource`] is a transparent wrapper around a valid `bindings::resource`.74#[repr(transparent)]75pub struct Resource(Opaque<bindings::resource>);7677impl Resource {78/// Creates a reference to a [`Resource`] from a valid pointer.79///80/// # Safety81///82/// The caller must ensure that for the duration of 'a, the pointer will83/// point at a valid `bindings::resource`.84///85/// The caller must also ensure that the [`Resource`] is only accessed via the86/// returned reference for the duration of 'a.87pub(crate) const unsafe fn from_raw<'a>(ptr: *mut bindings::resource) -> &'a Self {88// SAFETY: Self is a transparent wrapper around `Opaque<bindings::resource>`.89unsafe { &*ptr.cast() }90}9192/// Requests a resource region.93///94/// Exclusive access will be given and the region will be marked as busy.95/// Further calls to [`Self::request_region`] will return [`None`] if96/// the region, or a part of it, is already in use.97pub fn request_region(98&self,99start: ResourceSize,100size: ResourceSize,101name: CString,102flags: Flags,103) -> Option<Region> {104// SAFETY:105// - Safe as per the invariant of `Resource`.106// - `__request_region` will store a reference to the name, but that is107// safe as we own it and it will not be dropped until the `Region` is108// dropped.109let region = unsafe {110bindings::__request_region(111self.0.get(),112start,113size,114name.as_char_ptr(),115flags.0 as c_int,116)117};118119Some(Region {120resource: NonNull::new(region)?,121_name: name,122})123}124125/// Returns the size of the resource.126pub fn size(&self) -> ResourceSize {127let inner = self.0.get();128// SAFETY: Safe as per the invariants of `Resource`.129unsafe { bindings::resource_size(inner) }130}131132/// Returns the start address of the resource.133pub fn start(&self) -> ResourceSize {134let inner = self.0.get();135// SAFETY: Safe as per the invariants of `Resource`.136unsafe { (*inner).start }137}138139/// Returns the name of the resource.140pub fn name(&self) -> Option<&CStr> {141let inner = self.0.get();142143// SAFETY: Safe as per the invariants of `Resource`.144let name = unsafe { (*inner).name };145146if name.is_null() {147return None;148}149150// SAFETY: In the C code, `resource::name` either contains a null151// pointer or points to a valid NUL-terminated C string, and at this152// point we know it is not null, so we can safely convert it to a153// `CStr`.154Some(unsafe { CStr::from_char_ptr(name) })155}156157/// Returns the flags associated with the resource.158pub fn flags(&self) -> Flags {159let inner = self.0.get();160// SAFETY: Safe as per the invariants of `Resource`.161let flags = unsafe { (*inner).flags };162163Flags(flags)164}165}166167// SAFETY: `Resource` only holds a pointer to a C `struct resource`, which is168// safe to be used from any thread.169unsafe impl Send for Resource {}170171// SAFETY: `Resource` only holds a pointer to a C `struct resource`, references172// to which are safe to be used from any thread.173unsafe impl Sync for Resource {}174175/// Resource flags as stored in the C `struct resource::flags` field.176///177/// They can be combined with the operators `|`, `&`, and `!`.178///179/// Values can be used from the associated constants such as180/// [`Flags::IORESOURCE_IO`].181#[derive(Clone, Copy, PartialEq)]182pub struct Flags(c_ulong);183184impl Flags {185/// Check whether `flags` is contained in `self`.186pub fn contains(self, flags: Flags) -> bool {187(self & flags) == flags188}189}190191impl core::ops::BitOr for Flags {192type Output = Self;193fn bitor(self, rhs: Self) -> Self::Output {194Self(self.0 | rhs.0)195}196}197198impl core::ops::BitAnd for Flags {199type Output = Self;200fn bitand(self, rhs: Self) -> Self::Output {201Self(self.0 & rhs.0)202}203}204205impl core::ops::Not for Flags {206type Output = Self;207fn not(self) -> Self::Output {208Self(!self.0)209}210}211212impl Flags {213/// PCI/ISA I/O ports.214pub const IORESOURCE_IO: Flags = Flags::new(bindings::IORESOURCE_IO);215216/// Resource is software muxed.217pub const IORESOURCE_MUXED: Flags = Flags::new(bindings::IORESOURCE_MUXED);218219/// Resource represents a memory region.220pub const IORESOURCE_MEM: Flags = Flags::new(bindings::IORESOURCE_MEM);221222/// Resource represents a memory region that must be ioremaped using `ioremap_np`.223pub const IORESOURCE_MEM_NONPOSTED: Flags = Flags::new(bindings::IORESOURCE_MEM_NONPOSTED);224225const fn new(value: u32) -> Self {226crate::build_assert!(value as u64 <= c_ulong::MAX as u64);227Flags(value as c_ulong)228}229}230231232