ax_driver/
binding_info.rs1use 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 irqs: Vec<BindingIrqBinding>,
10}
11
12#[derive(Clone, Debug, Eq, PartialEq)]
13pub struct BindingIrqBinding {
14 pub source_id: usize,
15 pub irq: BindingIrq,
16}
17
18#[derive(Clone, Debug, Eq, PartialEq)]
19pub enum BindingIrq {
20 Id(IrqId),
21 Source(BindingIrqSource),
22}
23
24#[derive(Clone, Debug, Eq, PartialEq)]
25pub enum BindingIrqSource {
26 AcpiGsi(u32),
27 AcpiGsiRoute(AcpiGsiRoute),
28 FdtInterrupt(FdtIrqSpec),
29}
30
31#[derive(Clone, Debug, Eq, PartialEq)]
33pub struct FdtIrqSpec {
34 pub controller: DeviceId,
35 pub cells: Vec<u32>,
36}
37
38#[derive(Clone, Copy, Debug, Eq, PartialEq)]
39#[cfg(feature = "pci")]
40pub enum PciIrqRequirement {
41 Optional,
42 Required,
43}
44
45impl BindingInfo {
46 pub const fn empty() -> Self {
47 Self { irqs: Vec::new() }
48 }
49
50 pub fn with_irq(irq: Option<usize>) -> Result<Self, irq_framework::IrqError> {
51 Ok(Self::with_binding_irq(
52 irq.map(BindingIrq::try_legacy).transpose()?,
53 ))
54 }
55
56 pub fn with_irq_id(irq: Option<IrqId>) -> Self {
57 Self::with_binding_irq(irq.map(BindingIrq::id))
58 }
59
60 pub fn with_binding_irq(irq: Option<BindingIrq>) -> Self {
61 match irq {
62 Some(irq) => Self::with_irq_sources([(0, irq)]),
63 None => Self::empty(),
64 }
65 }
66
67 pub fn with_irq_sources(irqs: impl IntoIterator<Item = (usize, BindingIrq)>) -> Self {
68 Self {
69 irqs: irqs
70 .into_iter()
71 .map(|(source_id, irq)| BindingIrqBinding { source_id, irq })
72 .collect(),
73 }
74 }
75
76 pub fn irq(&self) -> Option<&BindingIrq> {
77 self.irq_for_source(0)
78 .or_else(|| self.irqs.first().map(|binding| &binding.irq))
79 }
80
81 pub fn irq_cloned(&self) -> Option<BindingIrq> {
82 self.irq().cloned()
83 }
84
85 pub fn irq_for_source(&self, source_id: usize) -> Option<&BindingIrq> {
86 self.irqs
87 .iter()
88 .find(|binding| binding.source_id == source_id)
89 .map(|binding| &binding.irq)
90 }
91
92 pub fn irq_for_source_cloned(&self, source_id: usize) -> Option<BindingIrq> {
93 self.irq_for_source(source_id).cloned()
94 }
95
96 pub fn irq_sources(&self) -> &[BindingIrqBinding] {
97 &self.irqs
98 }
99
100 pub fn irq_num(&self) -> Option<usize> {
101 self.irq().and_then(BindingIrq::legacy_num)
102 }
103
104 pub fn irq_num_for_source(&self, source_id: usize) -> Option<usize> {
105 self.irq_for_source(source_id)
106 .and_then(BindingIrq::legacy_num)
107 }
108}
109
110impl BindingIrq {
111 pub const fn id(id: IrqId) -> Self {
112 Self::Id(id)
113 }
114
115 pub fn try_legacy(raw: usize) -> Result<Self, irq_framework::IrqError> {
116 Ok(Self::Id(try_legacy_irq(raw)?))
117 }
118
119 pub const fn acpi_gsi(gsi: u32) -> Self {
120 Self::Source(BindingIrqSource::AcpiGsi(gsi))
121 }
122
123 pub const fn acpi_gsi_route(route: AcpiGsiRoute) -> Self {
124 Self::Source(BindingIrqSource::AcpiGsiRoute(route))
125 }
126
127 pub fn fdt_interrupt_with_controller(controller: DeviceId, cells: impl Into<Vec<u32>>) -> Self {
128 Self::Source(BindingIrqSource::fdt_interrupt_with_controller(
129 controller, cells,
130 ))
131 }
132
133 pub const fn irq_id(&self) -> Option<IrqId> {
134 match self {
135 Self::Id(id) => Some(*id),
136 Self::Source(_) => None,
137 }
138 }
139
140 pub fn legacy_num(&self) -> Option<usize> {
141 self.irq_id().and_then(legacy_irq_raw)
142 }
143
144 pub fn as_irq_source(&self) -> Option<IrqSource> {
145 match self {
146 Self::Id(_) => None,
147 Self::Source(source) => source.as_irq_source(),
148 }
149 }
150}
151
152impl BindingIrqSource {
153 pub const fn acpi_gsi(gsi: u32) -> Self {
154 Self::AcpiGsi(gsi)
155 }
156
157 pub const fn acpi_gsi_route(route: AcpiGsiRoute) -> Self {
158 Self::AcpiGsiRoute(route)
159 }
160
161 pub fn fdt_interrupt_with_controller(controller: DeviceId, cells: impl Into<Vec<u32>>) -> Self {
162 Self::FdtInterrupt(FdtIrqSpec {
163 controller,
164 cells: cells.into(),
165 })
166 }
167
168 pub fn as_irq_source(&self) -> Option<IrqSource> {
169 match self {
170 Self::AcpiGsi(gsi) => Some(IrqSource::AcpiGsi(*gsi)),
171 Self::AcpiGsiRoute(route) => Some(IrqSource::AcpiGsiRoute(*route)),
172 Self::FdtInterrupt(_) => None,
173 }
174 }
175}
176
177impl From<rdif_intc::AcpiGsiRoute> for BindingIrq {
178 fn from(route: rdif_intc::AcpiGsiRoute) -> Self {
179 Self::Source(BindingIrqSource::from(route))
180 }
181}
182
183impl From<rdif_intc::AcpiGsiRoute> for BindingIrqSource {
184 fn from(route: rdif_intc::AcpiGsiRoute) -> Self {
185 Self::AcpiGsiRoute(AcpiGsiRoute {
186 gsi: route.gsi,
187 vector: route.vector,
188 controller: match route.controller {
189 rdif_intc::AcpiGsiController::IoApic => irq_framework::AcpiGsiController::IoApic,
190 rdif_intc::AcpiGsiController::PchPic => irq_framework::AcpiGsiController::PchPic,
191 },
192 controller_id: route.controller_id,
193 controller_address: route.controller_address,
194 controller_input: route.controller_input,
195 trigger: match route.trigger {
196 rdif_intc::AcpiIrqTrigger::Edge => irq_framework::AcpiIrqTrigger::Edge,
197 rdif_intc::AcpiIrqTrigger::Level => irq_framework::AcpiIrqTrigger::Level,
198 },
199 polarity: match route.polarity {
200 rdif_intc::AcpiIrqPolarity::ActiveHigh => {
201 irq_framework::AcpiIrqPolarity::ActiveHigh
202 }
203 rdif_intc::AcpiIrqPolarity::ActiveLow => irq_framework::AcpiIrqPolarity::ActiveLow,
204 },
205 })
206 }
207}