use super::common::Feature;
use crate::{
Hal, Result,
queue::VirtQueue,
transport::{InterruptStatus, Transport},
};
const QUEUE_IDX: u16 = 0;
const QUEUE_SIZE: usize = 8;
const SUPPORTED_FEATURES: Feature = Feature::RING_INDIRECT_DESC
.union(Feature::RING_EVENT_IDX)
.union(Feature::VERSION_1);
pub struct VirtIORng<H: Hal, T: Transport> {
transport: T,
queue: VirtQueue<H, QUEUE_SIZE>,
}
impl<H: Hal, T: Transport> VirtIORng<H, T> {
pub fn new(mut transport: T) -> Result<Self> {
let feat = transport.begin_init(SUPPORTED_FEATURES);
let queue = VirtQueue::new(
&mut transport,
QUEUE_IDX,
feat.contains(Feature::RING_INDIRECT_DESC),
feat.contains(Feature::RING_EVENT_IDX),
)?;
transport.finish_init();
Ok(Self { transport, queue })
}
pub fn request_entropy(&mut self, dst: &mut [u8]) -> Result<usize> {
let num = self
.queue
.add_notify_wait_pop(&[], &mut [dst], &mut self.transport)?;
Ok(num as usize)
}
pub fn enable_interrupts(&mut self) {
self.queue.set_dev_notify(true);
}
pub fn disable_interrupts(&mut self) {
self.queue.set_dev_notify(false);
}
pub fn ack_interrupt(&mut self) -> InterruptStatus {
self.transport.ack_interrupt()
}
}
impl<H: Hal, T: Transport> Drop for VirtIORng<H, T> {
fn drop(&mut self) {
self.transport.queue_unset(QUEUE_IDX);
}
}