//! Bounded PCI INTx swizzle and logical interrupt-route ownership. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { InvalidPin, InvalidSlot, InvalidSpi, DuplicateSource, Full, MissingRoute, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Source { pub bus: u8, pub device: u8, pub function: u8, pub pin: u8, } impl Source { pub fn new(bus: u8, device: u8, function: u8, pin: u8) -> Result { if device > 31 || function > 7 { return Err(Error::InvalidSlot); } if !(1..=4).contains(&pin) { return Err(Error::InvalidPin); } Ok(Self {bus, device, function, pin}) } } pub fn swizzle(pin: u8, device: u8) -> Result { if !(1..=4).contains(&pin) { return Err(Error::InvalidPin); } if device > 31 { return Err(Error::InvalidSlot); } Ok(((pin - 1 + device) & 3) + 1) } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Route { pub source: Source, pub spi: u32 } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Snapshot { pub entries: [Option; N], pub count: usize, } pub struct RouteTable { entries: [Option; N], count: usize, } impl RouteTable { pub const fn new() -> Self { Self {entries: [None; N], count: 0} } pub const fn count(&self) -> usize { self.count } pub fn snapshot(&self) -> Snapshot { Snapshot {entries: self.entries, count: self.count} } pub fn claim(&mut self, source: Source, spi: u32) -> Result { if !(32..=1019).contains(&spi) { return Err(Error::InvalidSpi); } if self.entries.iter().flatten().any(|old| old.source == source) { return Err(Error::DuplicateSource); } let slot = self.entries.iter_mut().find(|slot| slot.is_none()) .ok_or(Error::Full)?; let route = Route {source, spi}; *slot = Some(route); self.count += 1; Ok(route) } pub fn resolve(&self, source: Source) -> Result { self.entries.iter().flatten().find(|route| route.source == source) .map(|route| route.spi).ok_or(Error::MissingRoute) } pub fn release(&mut self, route: Route) -> Result<(), Error> { let slot = self.entries.iter_mut().find(|entry| **entry == Some(route)) .ok_or(Error::MissingRoute)?; *slot = None; self.count -= 1; Ok(()) } }