Skip to main content

ax_driver/
binding_info.rs

1use alloc::vec::Vec;
2
3use axklib::irq::{legacy_irq_raw, try_legacy_irq};
4use irq_framework::{AcpiGsiRoute, IrqId, IrqSource};
5use rdrive::DeviceId;
6
7#[derive(Clone, Debug, Default, PartialEq, Eq)]
8pub struct BindingInfo {
9    irq: Option<BindingIrq>,
10}
11
12#[derive(Clone, Debug, Eq, PartialEq)]
13pub enum BindingIrq {
14    Id(IrqId),
15    Source(BindingIrqSource),
16}
17
18#[derive(Clone, Debug, Eq, PartialEq)]
19pub enum BindingIrqSource {
20    AcpiGsi(u32),
21    AcpiGsiRoute(AcpiGsiRoute),
22    FdtInterrupt(FdtIrqSpec),
23}
24
25/// Fully described FDT interrupt specifier.
26#[derive(Clone, Debug, Eq, PartialEq)]
27pub struct FdtIrqSpec {
28    pub controller: DeviceId,
29    pub cells: Vec<u32>,
30}
31
32#[derive(Clone, Copy, Debug, Eq, PartialEq)]
33#[cfg(feature = "pci")]
34pub enum PciIrqRequirement {
35    Optional,
36    Required,
37}
38
39impl BindingInfo {
40    pub const fn empty() -> Self {
41        Self { irq: None }
42    }
43
44    pub fn with_irq(irq: Option<usize>) -> Result<Self, irq_framework::IrqError> {
45        Ok(Self {
46            irq: irq.map(BindingIrq::try_legacy).transpose()?,
47        })
48    }
49
50    pub fn with_irq_id(irq: Option<IrqId>) -> Self {
51        Self {
52            irq: irq.map(BindingIrq::id),
53        }
54    }
55
56    pub fn with_binding_irq(irq: Option<BindingIrq>) -> Self {
57        Self { irq }
58    }
59
60    pub fn irq(&self) -> Option<&BindingIrq> {
61        self.irq.as_ref()
62    }
63
64    pub fn irq_cloned(&self) -> Option<BindingIrq> {
65        self.irq.clone()
66    }
67
68    pub fn irq_num(&self) -> Option<usize> {
69        self.irq.as_ref().and_then(BindingIrq::legacy_num)
70    }
71}
72
73impl BindingIrq {
74    pub const fn id(id: IrqId) -> Self {
75        Self::Id(id)
76    }
77
78    pub fn try_legacy(raw: usize) -> Result<Self, irq_framework::IrqError> {
79        Ok(Self::Id(try_legacy_irq(raw)?))
80    }
81
82    pub const fn acpi_gsi(gsi: u32) -> Self {
83        Self::Source(BindingIrqSource::AcpiGsi(gsi))
84    }
85
86    pub const fn acpi_gsi_route(route: AcpiGsiRoute) -> Self {
87        Self::Source(BindingIrqSource::AcpiGsiRoute(route))
88    }
89
90    pub fn fdt_interrupt_with_controller(controller: DeviceId, cells: impl Into<Vec<u32>>) -> Self {
91        Self::Source(BindingIrqSource::fdt_interrupt_with_controller(
92            controller, cells,
93        ))
94    }
95
96    pub const fn irq_id(&self) -> Option<IrqId> {
97        match self {
98            Self::Id(id) => Some(*id),
99            Self::Source(_) => None,
100        }
101    }
102
103    pub fn legacy_num(&self) -> Option<usize> {
104        self.irq_id().and_then(legacy_irq_raw)
105    }
106
107    pub fn as_irq_source(&self) -> Option<IrqSource> {
108        match self {
109            Self::Id(_) => None,
110            Self::Source(source) => source.as_irq_source(),
111        }
112    }
113}
114
115impl BindingIrqSource {
116    pub const fn acpi_gsi(gsi: u32) -> Self {
117        Self::AcpiGsi(gsi)
118    }
119
120    pub const fn acpi_gsi_route(route: AcpiGsiRoute) -> Self {
121        Self::AcpiGsiRoute(route)
122    }
123
124    pub fn fdt_interrupt_with_controller(controller: DeviceId, cells: impl Into<Vec<u32>>) -> Self {
125        Self::FdtInterrupt(FdtIrqSpec {
126            controller,
127            cells: cells.into(),
128        })
129    }
130
131    pub fn as_irq_source(&self) -> Option<IrqSource> {
132        match self {
133            Self::AcpiGsi(gsi) => Some(IrqSource::AcpiGsi(*gsi)),
134            Self::AcpiGsiRoute(route) => Some(IrqSource::AcpiGsiRoute(*route)),
135            Self::FdtInterrupt(_) => None,
136        }
137    }
138}
139
140impl From<rdif_intc::AcpiGsiRoute> for BindingIrq {
141    fn from(route: rdif_intc::AcpiGsiRoute) -> Self {
142        Self::Source(BindingIrqSource::from(route))
143    }
144}
145
146impl From<rdif_intc::AcpiGsiRoute> for BindingIrqSource {
147    fn from(route: rdif_intc::AcpiGsiRoute) -> Self {
148        Self::AcpiGsiRoute(AcpiGsiRoute {
149            gsi: route.gsi,
150            vector: route.vector,
151            controller: match route.controller {
152                rdif_intc::AcpiGsiController::IoApic => irq_framework::AcpiGsiController::IoApic,
153                rdif_intc::AcpiGsiController::PchPic => irq_framework::AcpiGsiController::PchPic,
154            },
155            controller_id: route.controller_id,
156            controller_address: route.controller_address,
157            controller_input: route.controller_input,
158            trigger: match route.trigger {
159                rdif_intc::AcpiIrqTrigger::Edge => irq_framework::AcpiIrqTrigger::Edge,
160                rdif_intc::AcpiIrqTrigger::Level => irq_framework::AcpiIrqTrigger::Level,
161            },
162            polarity: match route.polarity {
163                rdif_intc::AcpiIrqPolarity::ActiveHigh => {
164                    irq_framework::AcpiIrqPolarity::ActiveHigh
165                }
166                rdif_intc::AcpiIrqPolarity::ActiveLow => irq_framework::AcpiIrqPolarity::ActiveLow,
167            },
168        })
169    }
170}