pub mod pci;
use super::{cells::AddressCells, PHandle, Property};
use crate::{
cell_collector::{BuildCellCollector, CellCollector, CollectCellsError},
helpers::{FallibleNode, FallibleRoot},
nodes::{root::Root, Node},
parsing::{aligned::AlignedParser, BigEndianU32, NoPanic, Panic, ParserWithMode},
FdtError,
};
pub enum Interrupts<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)> {
Legacy(LegacyInterrupts<'a, P>),
Extended(ExtendedInterrupts<'a, P>),
}
impl<'a, P: ParserWithMode<'a>> Property<'a, P> for Interrupts<'a, P> {
fn parse(node: FallibleNode<'a, P>, root: FallibleRoot<'a, P>) -> Result<Option<Self>, FdtError> {
match ExtendedInterrupts::parse(node, root)? {
Some(extended) => Ok(Some(Self::Extended(extended))),
None => match LegacyInterrupts::parse(node, root)? {
Some(legacy) => Ok(Some(Self::Legacy(legacy))),
None => Ok(None),
},
}
}
}
pub struct LegacyInterrupts<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)> {
interrupt_parent: InterruptParent<'a, P>,
interrupt_cells: InterruptCells,
encoded_array: &'a [u8],
}
impl<'a, P: ParserWithMode<'a>> LegacyInterrupts<'a, P> {
#[allow(missing_docs)]
pub fn interrupt_parent(self) -> InterruptParent<'a, P> {
self.interrupt_parent
}
#[allow(missing_docs)]
pub fn iter<I: CellCollector>(self) -> LegacyInterruptsIter<'a, I> {
LegacyInterruptsIter {
interrupt_cells: self.interrupt_cells,
encoded_array: self.encoded_array,
_collector: core::marker::PhantomData,
}
}
}
impl<'a, P: ParserWithMode<'a>> Property<'a, P> for LegacyInterrupts<'a, P> {
fn parse(node: FallibleNode<'a, P>, root: FallibleRoot<'a, P>) -> Result<Option<Self>, FdtError> {
match node.properties()?.find("interrupts")? {
Some(interrupts) => {
let interrupt_parent = match InterruptParent::<(P::Parser, NoPanic)>::parse(node, root)? {
Some(p) => p,
None => return Err(FdtError::MissingRequiredProperty("interrupt-parent")),
};
let Some(interrupt_cells) = interrupt_parent.property::<InterruptCells>()? else {
return Err(FdtError::MissingRequiredProperty("interrupt-cells"));
};
if interrupts.value.len() % (interrupt_cells.as_byte_count()) != 0 {
return Err(FdtError::InvalidPropertyValue);
}
Ok(Some(Self {
interrupt_parent: InterruptParent(interrupt_parent.0.alt()),
interrupt_cells,
encoded_array: interrupts.value,
}))
}
None => Ok(None),
}
}
}
impl<'a, P: ParserWithMode<'a>> Copy for LegacyInterrupts<'a, P> {}
impl<'a, P: ParserWithMode<'a>> Clone for LegacyInterrupts<'a, P> {
fn clone(&self) -> Self {
*self
}
}
#[allow(missing_docs)]
pub struct LegacyInterruptsIter<'a, I: CellCollector> {
interrupt_cells: InterruptCells,
encoded_array: &'a [u8],
_collector: core::marker::PhantomData<*mut I>,
}
impl<'a, I: CellCollector> Iterator for LegacyInterruptsIter<'a, I> {
type Item = Result<I::Output, CollectCellsError>;
fn next(&mut self) -> Option<Self::Item> {
let encoded_specifier = self.encoded_array.get(..self.interrupt_cells.as_byte_count())?;
let mut specifier_collector = <I as CellCollector>::Builder::default();
for encoded_specifier in encoded_specifier.chunks_exact(4) {
if let Err(e) = specifier_collector.push(u32::from_be_bytes(encoded_specifier.try_into().unwrap())) {
return Some(Err(e));
}
}
self.encoded_array = self.encoded_array.get(self.interrupt_cells.as_byte_count()..)?;
Some(Ok(I::map(specifier_collector.finish())))
}
}
pub struct ExtendedInterrupts<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)> {
root: Root<'a, P>,
encoded_array: &'a [u8],
}
impl<'a, P: ParserWithMode<'a>> ExtendedInterrupts<'a, P> {
#[allow(missing_docs)]
pub fn iter(self) -> ExtendedInterruptsIter<'a, P> {
ExtendedInterruptsIter { root: self.root, encoded_array: self.encoded_array }
}
}
impl<'a, P: ParserWithMode<'a>> Property<'a, P> for ExtendedInterrupts<'a, P> {
fn parse(node: FallibleNode<'a, P>, root: FallibleRoot<'a, P>) -> Result<Option<Self>, FdtError> {
match node.properties()?.find("interrupts-extended")? {
Some(interrupts) => {
Ok(Some(Self { encoded_array: interrupts.value, root: Root { node: root.node.alt() } }))
}
None => Ok(None),
}
}
}
#[allow(missing_docs)]
pub struct ExtendedInterruptsIter<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)> {
root: Root<'a, P>,
encoded_array: &'a [u8],
}
impl<'a, P: ParserWithMode<'a>> Iterator for ExtendedInterruptsIter<'a, P> {
type Item = P::Output<ExtendedInterrupt<'a, P>>;
#[track_caller]
fn next(&mut self) -> Option<Self::Item> {
let phandle = self
.encoded_array
.get(..4)
.map(|bytes| PHandle(BigEndianU32::from_be(u32::from_ne_bytes(bytes.try_into().unwrap()))))?;
self.encoded_array = self.encoded_array.get(4..)?;
let res = crate::tryblock!({
let root: FallibleRoot<'a, P> = Root { node: self.root.node.fallible() };
let Some(interrupt_parent) = root.resolve_phandle(phandle)? else {
return Err(FdtError::MissingPHandleNode(phandle.0.to_ne()));
};
let Some(interrupt_cells) = interrupt_parent.property::<InterruptCells>()? else {
return Err(FdtError::MissingRequiredProperty("#interrupt-cells"));
};
let cells_length = interrupt_cells.as_byte_count();
let encoded_array = match self.encoded_array.get(..cells_length) {
Some(bytes) => bytes,
None => return Ok(None),
};
self.encoded_array = match self.encoded_array.get(cells_length..) {
Some(bytes) => bytes,
None => return Ok(None),
};
Ok(Some(ExtendedInterrupt {
interrupt_parent: InterruptParent(interrupt_parent.alt()),
interrupt_cells,
encoded_array,
}))
});
#[allow(clippy::manual_map)]
match res.transpose() {
Some(output) => Some(P::to_output(output)),
None => None,
}
}
}
pub struct ExtendedInterrupt<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)> {
interrupt_parent: InterruptParent<'a, P>,
interrupt_cells: InterruptCells,
encoded_array: &'a [u8],
}
#[allow(missing_docs)]
impl<'a, P: ParserWithMode<'a>> ExtendedInterrupt<'a, P> {
pub fn interrupt_parent(self) -> InterruptParent<'a, P> {
self.interrupt_parent
}
pub fn interrupt_cells(self) -> InterruptCells {
self.interrupt_cells
}
pub fn interrupt_specifier(self) -> InterruptSpecifier<'a> {
InterruptSpecifier { interrupt_cells: self.interrupt_cells, encoded_array: self.encoded_array }
}
}
pub struct InterruptSpecifier<'a> {
interrupt_cells: InterruptCells,
encoded_array: &'a [u8],
}
impl<'a> InterruptSpecifier<'a> {
pub fn collect_to<C: CellCollector>(self) -> Result<<C as CellCollector>::Output, CollectCellsError> {
let mut collector = <C as CellCollector>::Builder::default();
for chunk in self.encoded_array.chunks_exact(4) {
collector.push(u32::from_be_bytes(chunk.try_into().unwrap()))?;
}
Ok(C::map(collector.finish()))
}
pub fn iter(self) -> InterruptSpecifierIter<'a> {
InterruptSpecifierIter { encoded_array: self.encoded_array }
}
pub fn iter_pairs(self) -> Option<InterruptSpecifierIterPairs<'a>> {
if self.interrupt_cells.0 != 2 {
return None;
}
Some(InterruptSpecifierIterPairs { encoded_array: self.encoded_array })
}
pub fn single(self) -> Option<u32> {
if self.interrupt_cells.0 != 1 {
return None;
}
self.iter().next()
}
pub fn pair(self) -> Option<(u32, u32)> {
if self.interrupt_cells.0 != 2 {
return None;
}
let mut iter = self.into_iter();
Some((iter.next()?, iter.next()?))
}
}
impl<'a> IntoIterator for InterruptSpecifier<'a> {
type IntoIter = InterruptSpecifierIter<'a>;
type Item = u32;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub struct InterruptSpecifierIter<'a> {
encoded_array: &'a [u8],
}
impl<'a> Iterator for InterruptSpecifierIter<'a> {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.encoded_array.is_empty() {
return None;
}
let next = self.encoded_array.get(..4)?;
self.encoded_array = self.encoded_array.get(4..)?;
Some(u32::from_be_bytes(next.try_into().unwrap()))
}
}
pub struct InterruptSpecifierIterPairs<'a> {
encoded_array: &'a [u8],
}
impl<'a> Iterator for InterruptSpecifierIterPairs<'a> {
type Item = (u32, u32);
fn next(&mut self) -> Option<Self::Item> {
if self.encoded_array.is_empty() {
return None;
}
let (next, rest) = self.encoded_array.split_at_checked(8)?;
self.encoded_array = rest;
let (first, second) = next.split_at(4);
Some((u32::from_be_bytes(first.try_into().unwrap()), u32::from_be_bytes(second.try_into().unwrap())))
}
}
pub struct InterruptParent<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)>(Node<'a, P>);
impl<'a, P: ParserWithMode<'a>> Copy for InterruptParent<'a, P> {}
impl<'a, P: ParserWithMode<'a>> Clone for InterruptParent<'a, P> {
fn clone(&self) -> Self {
*self
}
}
impl<'a, P: ParserWithMode<'a>> core::ops::Deref for InterruptParent<'a, P> {
type Target = Node<'a, P>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, P: ParserWithMode<'a>> core::ops::DerefMut for InterruptParent<'a, P> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'a, P: ParserWithMode<'a>> Property<'a, P> for InterruptParent<'a, P> {
fn parse(node: FallibleNode<'a, P>, root: FallibleRoot<'a, P>) -> Result<Option<Self>, FdtError> {
match node.properties()?.find("interrupt-parent")? {
Some(phandle) => match root.resolve_phandle(PHandle(phandle.as_value()?))? {
Some(parent) => Ok(Some(Self(parent.alt()))),
None => Err(FdtError::MissingPHandleNode(phandle.as_value()?)),
},
None => Ok(node.parent().map(|n| Self(n.alt()))),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct InterruptCells(pub usize);
impl InterruptCells {
pub fn as_byte_count(self) -> usize {
self.0 * core::mem::size_of::<u32>()
}
}
impl<'a, P: ParserWithMode<'a>> Property<'a, P> for InterruptCells {
fn parse(node: FallibleNode<'a, P>, _: FallibleRoot<'a, P>) -> Result<Option<Self>, FdtError> {
match node.properties()?.find("#interrupt-cells")? {
Some(ic) => Ok(Some(Self(ic.as_value()?))),
None => Ok(None),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct InterruptMapMask<AddrMask: CellCollector, IntMask: CellCollector> {
address_mask: AddrMask::Output,
interrupt_specifier_mask: IntMask::Output,
}
impl<AddrMask: CellCollector, IntMask: CellCollector> InterruptMapMask<AddrMask, IntMask> {
pub fn mask(
&self,
address: <AddrMask as CellCollector>::Output,
interrupt_specifier: <IntMask as CellCollector>::Output,
) -> (<AddrMask as CellCollector>::Output, <IntMask as CellCollector>::Output)
where
<AddrMask as CellCollector>::Output: Clone
+ core::ops::BitAnd<<AddrMask as CellCollector>::Output, Output = <AddrMask as CellCollector>::Output>,
<IntMask as CellCollector>::Output:
Clone + core::ops::BitAnd<<IntMask as CellCollector>::Output, Output = <IntMask as CellCollector>::Output>,
{
(self.address_mask.clone() & address, self.interrupt_specifier_mask.clone() & interrupt_specifier)
}
}
impl<'a, AddrMask: CellCollector, IntMask: CellCollector, P: ParserWithMode<'a>> Property<'a, P>
for InterruptMapMask<AddrMask, IntMask>
{
fn parse(node: FallibleNode<'a, P>, _: FallibleRoot<'a, P>) -> Result<Option<Self>, FdtError> {
let address_cells =
node.property::<AddressCells>()?.ok_or(FdtError::MissingRequiredProperty("#address-cells"))?;
let interrupt_cells =
node.property::<InterruptCells>()?.ok_or(FdtError::MissingRequiredProperty("#interrupt-cells"))?;
match node.properties()?.find("interrupt-map-mask")? {
Some(prop) => {
if prop.value.len() % 4 != 0 {
return Err(FdtError::InvalidPropertyValue);
}
let mut address_collector = AddrMask::Builder::default();
let mut specifier_collector = IntMask::Builder::default();
let mut cells = prop.value.chunks_exact(4);
for chunk in cells.by_ref().take(address_cells.0) {
address_collector.push(u32::from_be_bytes(chunk.try_into().unwrap()))?;
}
for chunk in cells.take(interrupt_cells.0) {
specifier_collector.push(u32::from_be_bytes(chunk.try_into().unwrap()))?;
}
Ok(Some(Self {
address_mask: AddrMask::map(address_collector.finish()),
interrupt_specifier_mask: IntMask::map(specifier_collector.finish()),
}))
}
None => Ok(None),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct InterruptController;
impl<'a, P: ParserWithMode<'a>> Property<'a, P> for InterruptController {
fn parse(node: FallibleNode<'a, P>, _: FallibleRoot<'a, P>) -> Result<Option<Self>, FdtError> {
match node.properties()?.find("interrupt-controller")? {
Some(_) => Ok(Some(Self)),
None => Ok(None),
}
}
}
pub struct InterruptMap<
'a,
ChildUnitAddress: CellCollector,
ChildInterruptSpecifier: CellCollector = u32,
ParentUnitAddress: CellCollector = u64,
ParentInterruptSpecifier: CellCollector = u32,
P: ParserWithMode<'a> = (AlignedParser<'a>, Panic),
> {
address_cells: AddressCells,
interrupt_cells: InterruptCells,
node: FallibleNode<'a, P>,
encoded_map: &'a [u8],
_collectors: core::marker::PhantomData<*mut (
ChildUnitAddress,
ChildInterruptSpecifier,
ParentUnitAddress,
ParentInterruptSpecifier,
)>,
}
impl<
'a,
P: ParserWithMode<'a>,
CAddr: CellCollector,
CInt: CellCollector,
PAddr: CellCollector,
PInt: CellCollector,
> InterruptMap<'a, CAddr, CInt, PAddr, PInt, P>
{
pub fn iter(self) -> InterruptMapIter<'a, CAddr, CInt, PAddr, PInt, P> {
InterruptMapIter {
address_cells: self.address_cells,
interrupt_cells: self.interrupt_cells,
node: self.node,
encoded_map: self.encoded_map,
_collectors: core::marker::PhantomData,
}
}
pub fn iter_masked(
self,
mask: InterruptMapMask<CAddr, CInt>,
) -> MaskedInterruptMapIter<'a, CAddr, CInt, PAddr, PInt, P>
where
<CAddr as CellCollector>::Output:
Clone + core::ops::BitAnd<<CAddr as CellCollector>::Output, Output = <CAddr as CellCollector>::Output>,
<CInt as CellCollector>::Output:
Clone + core::ops::BitAnd<<CInt as CellCollector>::Output, Output = <CInt as CellCollector>::Output>,
{
MaskedInterruptMapIter {
address_cells: self.address_cells,
interrupt_cells: self.interrupt_cells,
node: self.node,
encoded_map: self.encoded_map,
mask,
_collectors: core::marker::PhantomData,
}
}
#[allow(clippy::type_complexity)]
pub fn find(
self,
client_unit_address: CAddr::Output,
child_interrupt_specifier: CInt::Output,
) -> P::Output<Option<InterruptMapEntry<'a, CAddr, CInt, PAddr, PInt, P>>>
where
CAddr::Output: PartialEq,
CInt::Output: PartialEq,
{
let this: InterruptMap<_, _, _, _, (P::Parser, NoPanic)> = InterruptMap {
address_cells: self.address_cells,
interrupt_cells: self.interrupt_cells,
node: self.node,
encoded_map: self.encoded_map,
_collectors: self._collectors,
};
P::to_output(
this.iter()
.find(|e| match e {
Err(_) => true,
Ok(entry) => {
entry.child_unit_address == client_unit_address
&& entry.child_interrupt_specifier == child_interrupt_specifier
}
})
.transpose()
.map(|e| {
e.map(|e| InterruptMapEntry::<_, _, _, _, P> {
child_unit_address: e.child_unit_address,
child_interrupt_specifier: e.child_interrupt_specifier,
interrupt_parent: e.interrupt_parent.alt(),
parent_unit_address: e.parent_unit_address,
parent_interrupt_specifier: e.parent_interrupt_specifier,
})
}),
)
}
}
impl<
'a,
P: ParserWithMode<'a>,
CAddr: CellCollector,
CInt: CellCollector,
PAddr: CellCollector,
PInt: CellCollector,
> Property<'a, P> for InterruptMap<'a, CAddr, CInt, PAddr, PInt, P>
{
fn parse(node: FallibleNode<'a, P>, _: FallibleRoot<'a, P>) -> Result<Option<Self>, FdtError> {
let Some(encoded_map) = node.properties()?.find("interrupt-map")? else { return Ok(None) };
let address_cells =
node.property::<AddressCells>()?.ok_or(FdtError::MissingRequiredProperty("#address-cells"))?;
let interrupt_cells =
node.property::<InterruptCells>()?.ok_or(FdtError::MissingRequiredProperty("#interrupt-cells"))?;
Ok(Some(InterruptMap {
address_cells,
interrupt_cells,
node: node.alt(),
encoded_map: encoded_map.value,
_collectors: core::marker::PhantomData,
}))
}
}
#[allow(missing_docs)]
pub struct InterruptMapIter<
'a,
CAddr: CellCollector,
CInt: CellCollector,
PAddr: CellCollector,
PInt: CellCollector,
P: ParserWithMode<'a> = (AlignedParser<'a>, Panic),
> {
address_cells: AddressCells,
interrupt_cells: InterruptCells,
node: FallibleNode<'a, P>,
encoded_map: &'a [u8],
_collectors: core::marker::PhantomData<*mut (CAddr, CInt, PAddr, PInt)>,
}
impl<
'a,
CAddr: CellCollector,
CInt: CellCollector,
PAddr: CellCollector,
PInt: CellCollector,
P: ParserWithMode<'a>,
> Iterator for InterruptMapIter<'a, CAddr, CInt, PAddr, PInt, P>
{
type Item = P::Output<InterruptMapEntry<'a, CAddr, CInt, PAddr, PInt, P>>;
#[track_caller]
fn next(&mut self) -> Option<Self::Item> {
let res = crate::tryblock!({
let child_addr_size = self.address_cells.0 * 4;
let child_intsp_size = self.interrupt_cells.as_byte_count();
let Some((child_address_iter, rest)) = self.encoded_map.split_at_checked(child_addr_size) else {
return Ok(None);
};
let Some((child_specifier_iter, rest)) = rest.split_at_checked(child_intsp_size) else {
return Ok(None);
};
let Some((interrupt_parent, rest)) = rest.split_at_checked(4) else {
return Ok(None);
};
let root = self.node.make_root::<(P::Parser, NoPanic)>()?;
let phandle = u32::from_ne_bytes(interrupt_parent.try_into().unwrap());
let interrupt_parent = root
.resolve_phandle(PHandle(BigEndianU32::from_be(phandle)))?
.ok_or(FdtError::MissingPHandleNode(phandle.swap_bytes()))?;
let parent_address_cells = interrupt_parent
.property::<AddressCells>()?
.ok_or(FdtError::MissingRequiredProperty("#address-cells"))?;
let parent_interrupt_cells = interrupt_parent
.property::<InterruptCells>()?
.ok_or(FdtError::MissingRequiredProperty("#interrupt-cells"))?;
let parent_addr_size = parent_address_cells.0 * 4;
let parent_intsp_size = parent_interrupt_cells.as_byte_count();
let Some((parent_address_iter, rest)) = rest.split_at_checked(parent_addr_size) else {
return Ok(None);
};
let Some((parent_specifier_iter, rest)) = rest.split_at_checked(parent_intsp_size) else {
return Ok(None);
};
self.encoded_map = rest;
let mut child_address_collector = CAddr::Builder::default();
for chunk in child_address_iter.chunks_exact(4) {
child_address_collector.push(u32::from_be_bytes(chunk.try_into().unwrap()))?;
}
let mut child_specifier_collector = CInt::Builder::default();
for chunk in child_specifier_iter.chunks_exact(4) {
child_specifier_collector.push(u32::from_be_bytes(chunk.try_into().unwrap()))?;
}
let mut parent_address_collector = PAddr::Builder::default();
for chunk in parent_address_iter.chunks_exact(4) {
parent_address_collector.push(u32::from_be_bytes(chunk.try_into().unwrap()))?;
}
let mut parent_specifier_collector = PInt::Builder::default();
for chunk in parent_specifier_iter.chunks_exact(4) {
parent_specifier_collector.push(u32::from_be_bytes(chunk.try_into().unwrap()))?;
}
Ok(Some(InterruptMapEntry {
interrupt_parent: interrupt_parent.alt(),
child_unit_address: CAddr::map(child_address_collector.finish()),
child_interrupt_specifier: CInt::map(child_specifier_collector.finish()),
parent_unit_address: PAddr::map(parent_address_collector.finish()),
parent_interrupt_specifier: PInt::map(parent_specifier_collector.finish()),
}))
});
#[allow(clippy::manual_map)]
match res.transpose() {
Some(output) => Some(P::to_output(output)),
None => None,
}
}
}
#[allow(missing_docs)]
pub struct MaskedInterruptMapIter<
'a,
CAddr: CellCollector,
CInt: CellCollector,
PAddr: CellCollector,
PInt: CellCollector,
P: ParserWithMode<'a> = (AlignedParser<'a>, Panic),
> where
<CAddr as CellCollector>::Output:
Clone + core::ops::BitAnd<<CAddr as CellCollector>::Output, Output = <CAddr as CellCollector>::Output>,
<CInt as CellCollector>::Output:
Clone + core::ops::BitAnd<<CInt as CellCollector>::Output, Output = <CInt as CellCollector>::Output>,
{
address_cells: AddressCells,
interrupt_cells: InterruptCells,
node: FallibleNode<'a, P>,
encoded_map: &'a [u8],
mask: InterruptMapMask<CAddr, CInt>,
_collectors: core::marker::PhantomData<*mut (CAddr, CInt, PAddr, PInt)>,
}
impl<
'a,
CAddr: CellCollector,
CInt: CellCollector,
PAddr: CellCollector,
PInt: CellCollector,
P: ParserWithMode<'a>,
> Iterator for MaskedInterruptMapIter<'a, CAddr, CInt, PAddr, PInt, P>
where
<CAddr as CellCollector>::Output:
Clone + core::ops::BitAnd<<CAddr as CellCollector>::Output, Output = <CAddr as CellCollector>::Output>,
<CInt as CellCollector>::Output:
Clone + core::ops::BitAnd<<CInt as CellCollector>::Output, Output = <CInt as CellCollector>::Output>,
{
type Item = P::Output<InterruptMapEntry<'a, CAddr, CInt, PAddr, PInt, P>>;
#[track_caller]
fn next(&mut self) -> Option<Self::Item> {
let res = crate::tryblock!({
let child_addr_size = self.address_cells.0 * 4;
let child_intsp_size = self.interrupt_cells.as_byte_count();
let Some((child_address_iter, rest)) = self.encoded_map.split_at_checked(child_addr_size) else {
return Ok(None);
};
let Some((child_specifier_iter, rest)) = rest.split_at_checked(child_intsp_size) else {
return Ok(None);
};
let Some((interrupt_parent, rest)) = rest.split_at_checked(4) else {
return Ok(None);
};
let root = self.node.make_root::<(P::Parser, NoPanic)>()?;
let phandle = u32::from_ne_bytes(interrupt_parent.try_into().unwrap());
let interrupt_parent = root
.resolve_phandle(PHandle(BigEndianU32::from_be(phandle)))?
.ok_or(FdtError::MissingPHandleNode(phandle.swap_bytes()))?;
let parent_address_cells = interrupt_parent
.property::<AddressCells>()?
.ok_or(FdtError::MissingRequiredProperty("#address-cells"))?;
let parent_interrupt_cells = interrupt_parent
.property::<InterruptCells>()?
.ok_or(FdtError::MissingRequiredProperty("#interrupt-cells"))?;
let parent_addr_size = parent_address_cells.0 * 4;
let parent_intsp_size = parent_interrupt_cells.as_byte_count();
let Some((parent_address_iter, rest)) = rest.split_at_checked(parent_addr_size) else {
return Ok(None);
};
let Some((parent_specifier_iter, rest)) = rest.split_at_checked(parent_intsp_size) else {
return Ok(None);
};
self.encoded_map = rest;
let mut child_address_collector = CAddr::Builder::default();
for chunk in child_address_iter.chunks_exact(4) {
child_address_collector.push(u32::from_be_bytes(chunk.try_into().unwrap()))?;
}
let mut child_specifier_collector = CInt::Builder::default();
for chunk in child_specifier_iter.chunks_exact(4) {
child_specifier_collector.push(u32::from_be_bytes(chunk.try_into().unwrap()))?;
}
let mut parent_address_collector = PAddr::Builder::default();
for chunk in parent_address_iter.chunks_exact(4) {
parent_address_collector.push(u32::from_be_bytes(chunk.try_into().unwrap()))?;
}
let mut parent_specifier_collector = PInt::Builder::default();
for chunk in parent_specifier_iter.chunks_exact(4) {
parent_specifier_collector.push(u32::from_be_bytes(chunk.try_into().unwrap()))?;
}
let child_unit_address = CAddr::map(child_address_collector.finish());
let child_interrupt_specifier = CInt::map(child_specifier_collector.finish());
let (child_unit_address, child_interrupt_specifier) =
self.mask.mask(child_unit_address, child_interrupt_specifier);
Ok(Some(InterruptMapEntry {
interrupt_parent: interrupt_parent.alt(),
child_unit_address,
child_interrupt_specifier,
parent_unit_address: PAddr::map(parent_address_collector.finish()),
parent_interrupt_specifier: PInt::map(parent_specifier_collector.finish()),
}))
});
#[allow(clippy::manual_map)]
match res.transpose() {
Some(output) => Some(P::to_output(output)),
None => None,
}
}
}
pub struct InterruptMapEntry<
'a,
CAddr: CellCollector,
CInt: CellCollector,
PAddr: CellCollector,
PInt: CellCollector,
P: ParserWithMode<'a>,
> {
pub interrupt_parent: Node<'a, P>,
pub child_unit_address: CAddr::Output,
pub child_interrupt_specifier: CInt::Output,
pub parent_unit_address: PAddr::Output,
pub parent_interrupt_specifier: PInt::Output,
}
impl<
'a,
P: ParserWithMode<'a>,
CAddr: CellCollector,
CInt: CellCollector,
PAddr: CellCollector,
PInt: CellCollector,
> Clone for InterruptMapEntry<'a, CAddr, CInt, PAddr, PInt, P>
where
CAddr::Output: Clone,
CInt::Output: Clone,
PAddr::Output: Clone,
PInt::Output: Clone,
{
fn clone(&self) -> Self {
Self {
child_unit_address: self.child_unit_address.clone(),
child_interrupt_specifier: self.child_interrupt_specifier.clone(),
interrupt_parent: self.interrupt_parent,
parent_unit_address: self.parent_unit_address.clone(),
parent_interrupt_specifier: self.parent_interrupt_specifier.clone(),
}
}
}
impl<
'a,
P: ParserWithMode<'a>,
CAddr: CellCollector,
CInt: CellCollector,
PAddr: CellCollector,
PInt: CellCollector,
> Copy for InterruptMapEntry<'a, CAddr, CInt, PAddr, PInt, P>
where
CAddr::Output: Copy,
CInt::Output: Copy,
PAddr::Output: Copy,
PInt::Output: Copy,
{
}