use super::ioctl;
use super::ioctl::Capability;
use super::QueueType;
use std::collections::BTreeSet;
use std::fs::File;
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
use std::{path::Path, sync::Mutex};
use thiserror::Error;
pub mod poller;
pub mod queue;
mod traits;
pub use traits::*;
#[derive(Default)]
pub struct DeviceConfig {
non_blocking_dqbuf: bool,
}
impl DeviceConfig {
pub fn new() -> Self {
Default::default()
}
pub fn non_blocking_dqbuf(self) -> Self {
DeviceConfig {
non_blocking_dqbuf: true,
}
}
}
pub struct Device {
capability: Capability,
fd: File,
used_queues: Mutex<BTreeSet<QueueType>>,
}
#[derive(Debug, Error)]
pub enum DeviceOpenError {
#[error("error while opening device")]
OpenError(#[from] nix::Error),
#[error("error while querying capabilities")]
QueryCapError(#[from] ioctl::QueryCapError),
}
impl Device {
fn new(fd: File) -> Result<Self, ioctl::QueryCapError> {
Ok(Device {
capability: ioctl::querycap(&fd)?,
fd,
used_queues: Mutex::new(BTreeSet::new()),
})
}
pub fn open(path: &Path, config: DeviceConfig) -> Result<Self, DeviceOpenError> {
use nix::fcntl::{open, OFlag};
use nix::sys::stat::Mode;
let flags = OFlag::O_RDWR
| OFlag::O_CLOEXEC
| if config.non_blocking_dqbuf {
OFlag::O_NONBLOCK
} else {
OFlag::empty()
};
let fd = open(path, flags, Mode::empty())?;
Ok(Device::new(unsafe { File::from_raw_fd(fd) })?)
}
pub fn caps(&self) -> &Capability {
&self.capability
}
}
impl AsFd for Device {
fn as_fd(&self) -> BorrowedFd {
self.fd.as_fd()
}
}
impl AsRawFd for Device {
fn as_raw_fd(&self) -> RawFd {
self.fd.as_raw_fd()
}
}