use std::{fs::OpenOptions, io, num::NonZero, path::Path, ptr::NonNull, time::Duration};
use nix::sys::mman::{MapFlags, ProtFlags, mmap, munmap};
use crate::{
XvcServer,
backends::memory_mapped::{MAP_SIZE, MemoryMappedBackend},
};
pub struct UioDriverBackend(MemoryMappedBackend);
impl UioDriverBackend {
pub fn new(path: impl AsRef<Path>, poll_timeout: Duration) -> io::Result<UioDriverBackend> {
let device_path = path.as_ref();
log::debug!("Opening UIO device: {}", device_path.display());
let file = OpenOptions::new().read(true).write(true).open(path)?;
log::debug!("UIO device file opened successfully");
let jtag = unsafe {
log::debug!("Mapping UIO memory (size=0x{:x})", MAP_SIZE);
let ptr = mmap(
None,
NonZero::new(MAP_SIZE).unwrap(),
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
MapFlags::MAP_SHARED,
file,
0,
)?;
log::info!("UIO memory mapped successfully");
ptr.as_ptr() as *mut u32
};
Ok(UioDriverBackend(MemoryMappedBackend::new(
jtag,
poll_timeout,
)))
}
}
impl Drop for UioDriverBackend {
fn drop(&mut self) {
if let Some(ptr) = NonNull::new(self.0.mem) {
unsafe {
let _ = munmap(ptr.cast(), MAP_SIZE);
}
}
}
}
impl XvcServer for UioDriverBackend {
type Err = io::Error;
fn set_tck(&self, period_ns: u32) -> Result<u32, Self::Err> {
Ok(period_ns)
}
fn shift(
&self,
num_bits: u32,
tms: &[u8],
tdi: &[u8],
tdo: &mut [u8],
) -> Result<(), Self::Err> {
self.0.shift_data(num_bits, tms, tdi, tdo)
}
}