#![deny(missing_docs)]
use std::any::Any;
use std::cmp::{Ord, PartialOrd};
use std::convert::TryFrom;
use std::sync::Mutex;
use self::resources::DeviceResources;
pub mod device_manager;
pub mod resources;
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct IoSize(pub u64);
impl IoSize {
#[inline]
pub fn raw_value(self) -> u64 {
self.0
}
}
impl From<u64> for IoSize {
#[inline]
fn from(size: u64) -> Self {
IoSize(size)
}
}
impl From<IoSize> for u64 {
#[inline]
fn from(size: IoSize) -> Self {
size.0
}
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct IoAddress(pub u64);
impl IoAddress {
#[inline]
pub fn raw_value(self) -> u64 {
self.0
}
}
impl From<u64> for IoAddress {
#[inline]
fn from(addr: u64) -> Self {
IoAddress(addr)
}
}
impl From<IoAddress> for u64 {
#[inline]
fn from(addr: IoAddress) -> Self {
addr.0
}
}
type PioAddressType = u16;
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct PioSize(pub PioAddressType);
impl PioSize {
#[inline]
pub fn raw_value(self) -> PioAddressType {
self.0
}
}
impl From<PioAddressType> for PioSize {
#[inline]
fn from(size: PioAddressType) -> Self {
PioSize(size)
}
}
impl From<PioSize> for PioAddressType {
#[inline]
fn from(size: PioSize) -> Self {
size.0
}
}
impl TryFrom<IoSize> for PioSize {
type Error = IoSize;
#[inline]
fn try_from(size: IoSize) -> Result<Self, Self::Error> {
if size.raw_value() <= std::u16::MAX as u64 {
Ok(PioSize(size.raw_value() as PioAddressType))
} else {
Err(size)
}
}
}
impl From<PioSize> for IoSize {
#[inline]
fn from(size: PioSize) -> Self {
IoSize(size.raw_value() as u64)
}
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct PioAddress(pub PioAddressType);
impl PioAddress {
#[inline]
pub fn raw_value(self) -> PioAddressType {
self.0
}
}
impl From<PioAddressType> for PioAddress {
#[inline]
fn from(addr: PioAddressType) -> Self {
PioAddress(addr)
}
}
impl From<PioAddress> for PioAddressType {
#[inline]
fn from(addr: PioAddress) -> Self {
addr.0
}
}
impl TryFrom<IoAddress> for PioAddress {
type Error = IoAddress;
#[inline]
fn try_from(addr: IoAddress) -> Result<Self, Self::Error> {
if addr.0 <= std::u16::MAX as u64 {
Ok(PioAddress(addr.raw_value() as PioAddressType))
} else {
Err(addr)
}
}
}
impl From<PioAddress> for IoAddress {
#[inline]
fn from(addr: PioAddress) -> Self {
IoAddress(addr.raw_value() as u64)
}
}
#[allow(unused_variables)]
pub trait DeviceIo: Send + Sync {
fn read(&self, base: IoAddress, offset: IoAddress, data: &mut [u8]) {}
fn write(&self, base: IoAddress, offset: IoAddress, data: &[u8]) {}
fn pio_read(&self, base: PioAddress, offset: PioAddress, data: &mut [u8]) {}
fn pio_write(&self, base: PioAddress, offset: PioAddress, data: &[u8]) {}
fn get_assigned_resources(&self) -> DeviceResources {
DeviceResources::new()
}
fn get_trapped_io_resources(&self) -> DeviceResources {
self.get_assigned_resources()
}
fn as_any(&self) -> &dyn Any;
}
#[allow(unused_variables)]
pub trait DeviceIoMut {
fn read(&mut self, base: IoAddress, offset: IoAddress, data: &mut [u8]) {}
fn write(&mut self, base: IoAddress, offset: IoAddress, data: &[u8]) {}
fn pio_read(&mut self, base: PioAddress, offset: PioAddress, data: &mut [u8]) {}
fn pio_write(&mut self, base: PioAddress, offset: PioAddress, data: &[u8]) {}
fn get_assigned_resources(&self) -> DeviceResources {
DeviceResources::new()
}
fn get_trapped_io_resources(&self) -> DeviceResources {
self.get_assigned_resources()
}
}
impl<T: DeviceIoMut + Send + 'static> DeviceIo for Mutex<T> {
fn read(&self, base: IoAddress, offset: IoAddress, data: &mut [u8]) {
self.lock().unwrap().read(base, offset, data)
}
fn write(&self, base: IoAddress, offset: IoAddress, data: &[u8]) {
self.lock().unwrap().write(base, offset, data)
}
fn pio_read(&self, base: PioAddress, offset: PioAddress, data: &mut [u8]) {
self.lock().unwrap().pio_read(base, offset, data)
}
fn pio_write(&self, base: PioAddress, offset: PioAddress, data: &[u8]) {
self.lock().unwrap().pio_write(base, offset, data)
}
fn get_assigned_resources(&self) -> DeviceResources {
self.lock().unwrap().get_assigned_resources()
}
fn get_trapped_io_resources(&self) -> DeviceResources {
self.lock().unwrap().get_trapped_io_resources()
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[cfg(test)]
mod tests {
use std::convert::TryFrom;
use std::sync::Arc;
use super::*;
#[derive(Default)]
struct MockDevice {
data: Mutex<u8>,
}
impl DeviceIo for MockDevice {
fn read(&self, _base: IoAddress, _offset: IoAddress, data: &mut [u8]) {
data[0] = *self.data.lock().unwrap();
}
fn write(&self, _base: IoAddress, _offset: IoAddress, data: &[u8]) {
*self.data.lock().unwrap() = data[0];
}
fn pio_read(&self, _base: PioAddress, _offset: PioAddress, data: &mut [u8]) {
data[0] = *self.data.lock().unwrap();
}
fn pio_write(&self, _base: PioAddress, _offset: PioAddress, data: &[u8]) {
*self.data.lock().unwrap() = data[0];
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[derive(Default)]
struct MockDeviceMut {
data: u8,
}
impl DeviceIoMut for MockDeviceMut {
fn read(&mut self, _base: IoAddress, _offset: IoAddress, data: &mut [u8]) {
data[0] = self.data;
}
fn write(&mut self, _base: IoAddress, _offset: IoAddress, data: &[u8]) {
self.data = data[0];
}
fn pio_read(&mut self, _base: PioAddress, _offset: PioAddress, data: &mut [u8]) {
data[0] = self.data;
}
fn pio_write(&mut self, _base: PioAddress, _offset: PioAddress, data: &[u8]) {
self.data = data[0];
}
}
fn register_device(device: Arc<dyn DeviceIo>) {
device.write(IoAddress(0), IoAddress(0), &[0x10u8]);
let mut buf = [0x0u8];
device.read(IoAddress(0), IoAddress(0), &mut buf);
assert_eq!(buf[0], 0x10);
{
device.pio_write(PioAddress(0), PioAddress(0), &[0x10u8]);
let mut buf = [0x0u8];
device.pio_read(PioAddress(0), PioAddress(0), &mut buf);
assert_eq!(buf[0], 0x10);
}
let resource = DeviceResources::new();
assert_eq!(resource, device.get_assigned_resources());
assert_eq!(resource, device.get_trapped_io_resources());
}
#[test]
fn test_device_io_adapter() {
let device = Arc::new(MockDevice::default());
register_device(device.clone());
assert_eq!(*device.data.lock().unwrap(), 0x010);
}
#[test]
fn test_device_io_mut_adapter() {
let device_mut = Arc::new(Mutex::new(MockDeviceMut::default()));
register_device(device_mut.clone());
assert_eq!(device_mut.lock().unwrap().data, 0x010);
}
#[test]
fn test_io_data_struct() {
let io_size = IoSize::from(0x1111u64);
assert_eq!(io_size.raw_value(), 0x1111u64);
assert_eq!(u64::from(io_size), 0x1111u64);
assert_eq!(io_size, io_size.clone());
let io_size1 = IoSize::from(0x1112u64);
assert!(io_size < io_size1);
let io_addr = IoAddress::from(0x1234u64);
assert_eq!(io_addr.raw_value(), 0x1234u64);
assert_eq!(u64::from(io_addr), 0x1234u64);
assert_eq!(io_addr, io_addr.clone());
let io_addr1 = IoAddress::from(0x1235u64);
assert!(io_addr < io_addr1);
}
#[test]
fn test_pio_data_struct() {
let pio_size = PioSize::from(0x1111u16);
assert_eq!(pio_size.raw_value(), 0x1111u16);
assert_eq!(u16::from(pio_size), 0x1111u16);
assert_eq!(pio_size, pio_size.clone());
let pio_size1 = PioSize::from(0x1112u16);
assert!(pio_size < pio_size1);
let pio_size = PioSize::try_from(IoSize(0x1111u64)).unwrap();
assert_eq!(pio_size.raw_value(), 0x1111u16);
assert!(PioSize::try_from(IoSize(std::u16::MAX as u64 + 1)).is_err());
let io_size = IoSize::from(PioSize::from(0x1111u16));
assert_eq!(io_size.raw_value(), 0x1111u64);
let pio_addr = PioAddress::from(0x1234u16);
assert_eq!(pio_addr.raw_value(), 0x1234u16);
assert_eq!(u16::from(pio_addr), 0x1234u16);
assert_eq!(pio_addr, pio_addr.clone());
let pio_addr1 = PioAddress::from(0x1235u16);
assert!(pio_addr < pio_addr1);
assert!(PioAddress::try_from(IoAddress::from(0x12_3456u64)).is_err());
assert!(PioAddress::try_from(IoAddress::from(0x1234u64)).is_ok());
assert_eq!(IoAddress::from(pio_addr).raw_value(), 0x1234u64);
}
}