use core::ops::Deref;
use crate::{
device::{
Bound,
Device, },
devres::Devres,
io::{
self,
resource::{
Region,
Resource, },
Mmio,
MmioRaw, },
prelude::*,
};
pub struct IoRequest<'a> {
device: &'a Device<Bound>,
resource: &'a Resource,
}
impl<'a> IoRequest<'a> {
pub(crate) unsafe fn new(device: &'a Device<Bound>, resource: &'a Resource) -> Self {
IoRequest { device, resource }
}
pub fn iomap_sized<const SIZE: usize>(self) -> impl PinInit<Devres<IoMem<SIZE>>, Error> + 'a {
IoMem::new(self)
}
pub fn iomap_exclusive_sized<const SIZE: usize>(
self,
) -> impl PinInit<Devres<ExclusiveIoMem<SIZE>>, Error> + 'a {
ExclusiveIoMem::new(self)
}
pub fn iomap(self) -> impl PinInit<Devres<IoMem<0>>, Error> + 'a {
Self::iomap_sized::<0>(self)
}
pub fn iomap_exclusive(self) -> impl PinInit<Devres<ExclusiveIoMem<0>>, Error> + 'a {
Self::iomap_exclusive_sized::<0>(self)
}
}
pub struct ExclusiveIoMem<const SIZE: usize> {
iomem: IoMem<SIZE>,
_region: Region,
}
impl<const SIZE: usize> ExclusiveIoMem<SIZE> {
fn ioremap(resource: &Resource) -> Result<Self> {
let start = resource.start();
let size = resource.size();
let name = resource.name().unwrap_or_default();
let region = resource
.request_region(
start,
size,
name.to_cstring()?,
io::resource::Flags::IORESOURCE_MEM,
)
.ok_or(EBUSY)?;
let iomem = IoMem::ioremap(resource)?;
let iomem = ExclusiveIoMem {
iomem,
_region: region,
};
Ok(iomem)
}
pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a {
let dev = io_request.device;
let res = io_request.resource;
Devres::new(dev, Self::ioremap(res))
}
}
impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> {
type Target = Mmio<SIZE>;
fn deref(&self) -> &Self::Target {
&self.iomem
}
}
pub struct IoMem<const SIZE: usize = 0> {
io: MmioRaw<SIZE>,
}
impl<const SIZE: usize> IoMem<SIZE> {
fn ioremap(resource: &Resource) -> Result<Self> {
let size = resource.size().try_into()?;
if size == 0 {
return Err(EINVAL);
}
let res_start = resource.start();
let addr = if resource
.flags()
.contains(io::resource::Flags::IORESOURCE_MEM_NONPOSTED)
{
unsafe { bindings::ioremap_np(res_start, size) }
} else {
unsafe { bindings::ioremap(res_start, size) }
};
if addr.is_null() {
return Err(ENOMEM);
}
let io = MmioRaw::new(addr as usize, size)?;
let io = IoMem { io };
Ok(io)
}
pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a {
let dev = io_request.device;
let res = io_request.resource;
Devres::new(dev, Self::ioremap(res))
}
}
impl<const SIZE: usize> Drop for IoMem<SIZE> {
fn drop(&mut self) {
unsafe { bindings::iounmap(self.io.addr() as *mut c_void) }
}
}
impl<const SIZE: usize> Deref for IoMem<SIZE> {
type Target = Mmio<SIZE>;
fn deref(&self) -> &Self::Target {
unsafe { Mmio::from_raw(&self.io) }
}
}