1use crate::error::PosixError;
2use crate::hal;
3use crate::sync::once::{LazyLock, OnceCell};
4use crate::sync::waiter::ParkedWaiter;
5
6pub use hal::can::{BusState, BusStatus, Diag, Filter, Frame, Mode};
7
8pub type Result<T> = core::result::Result<T, PosixError>;
9
10const CAN_BUS_MAX: usize = 2;
12
13pub struct Bus {
14 desc: hal::can::Device,
15 waiter: ParkedWaiter,
18}
19
20impl Bus {
21 fn slot(&self) -> u8 {
22 self.desc.index()
23 }
24}
25
26static SLOTS: [OnceCell<Bus>; CAN_BUS_MAX] = [const { OnceCell::new() }; CAN_BUS_MAX];
31
32#[derive(Clone, Copy)]
33struct BusInit {
34 slot: u8,
35 init: Result<()>,
36}
37
38static BUSES: LazyLock<[Option<BusInit>; CAN_BUS_MAX]> = LazyLock::new(|| {
39 let mut inits: [Option<BusInit>; CAN_BUS_MAX] = [None; CAN_BUS_MAX];
40 kprintln!(
41 "Found {} CAN bus entries",
42 hal::device_tree::CAN_REGISTRY.len()
43 );
44 for (i, entry) in hal::device_tree::CAN_REGISTRY.iter().enumerate() {
45 if i >= CAN_BUS_MAX {
46 kprintln!(" CAN registry exceeds CAN_BUS_MAX={CAN_BUS_MAX}");
47 break;
48 }
49 let bus = Bus {
50 desc: hal::can::Device::from_entry(entry),
51 waiter: ParkedWaiter::new(),
52 };
53 let bus_ref: &'static Bus = SLOTS[i].set_or_get(bus);
54 let init_result =
58 wire_irqs(bus_ref).and_then(|()| hal::can::init(&bus_ref.desc, Mode::Normal));
59 match init_result {
60 Ok(()) => kprintln!(" Initialized CAN bus at 0x{:x}", entry.instance),
61 Err(e) => kprintln!(
62 " Failed to initialize CAN bus at 0x{:x}: {:?}",
63 entry.instance,
64 e,
65 ),
66 }
67 inits[i] = Some(BusInit {
68 slot: bus_ref.slot(),
69 init: init_result,
70 });
71 }
72 inits
73});
74
75fn wire_irqs(bus: &'static Bus) -> Result<()> {
76 let ctx = bus as *const Bus as *mut ();
77 hal::can::register_irq_handler(&bus.desc, Some(kernel_dispatch), ctx)?;
78
79 let entry = bus.desc.entry();
80 let rx0_vector = entry.rx0_irq.irqn as usize + 16;
81 let rx1_vector = entry.rx1_irq.irqn as usize + 16;
82 let userdata = Some(bus as *const Bus as usize);
83 unsafe {
84 crate::irq::register_irq(rx0_vector, rx_kernel_handler, userdata)
85 .map_err(|_| PosixError::EIO)?;
86 crate::irq::register_irq(rx1_vector, rx_kernel_handler, userdata)
87 .map_err(|_| PosixError::EIO)?;
88 }
89 Ok(())
90}
91
92extern "C" fn kernel_dispatch(kind: hal::can::Irq, ctx: *mut ()) {
93 if !matches!(kind, hal::can::Irq::Rx0 | hal::can::Irq::Rx1) {
94 return;
95 }
96 if ctx.is_null() {
97 return;
98 }
99 let bus = unsafe { &*(ctx as *const Bus) };
101 bus.waiter.wake();
102}
103
104fn rx_kernel_handler(_ctx: *mut u8, _vector: usize, userdata: Option<usize>) {
105 let Some(ptr) = userdata else { return };
106 let bus = unsafe { &*(ptr as *const Bus) };
108 hal::can::dispatch_isr(bus.slot());
109}
110
111pub struct Device {
112 desc: hal::can::Device,
113}
114
115impl Device {
116 pub fn open(compatible: &str, ordinal: usize) -> Result<Self> {
117 let _ = LazyLock::force(&BUSES);
118
119 let desc = hal::can::get(compatible, ordinal)?;
120 let target_slot = desc.index();
121 for entry in BUSES.iter() {
122 if let Some(e) = entry {
123 if e.slot == target_slot {
124 return match e.init {
125 Ok(()) => Ok(Self { desc }),
126 Err(err) => Err(err),
127 };
128 }
129 }
130 }
131 Err(PosixError::ENODEV)
132 }
133
134 pub fn start(&self) -> Result<()> {
136 hal::can::start(&self.desc)
137 }
138
139 pub fn transmit(&self, frame: &Frame) -> Result<()> {
140 hal::can::transmit(&self.desc, frame)
141 }
142
143 pub fn receive(&self, out: &mut Frame) -> Result<bool> {
144 hal::can::receive(&self.desc, out)
145 }
146
147 pub fn configure_filter(&self, filter: &Filter) -> Result<()> {
149 hal::can::configure_filter(&self.desc, filter)
150 }
151
152 pub fn bus_status(&self) -> BusStatus {
153 hal::can::bus_status(&self.desc)
154 }
155
156 pub fn recover(&self) -> Result<()> {
157 hal::can::recover(&self.desc)
158 }
159
160 pub fn diag(&self) -> Diag {
161 hal::can::diag(&self.desc)
162 }
163
164 pub fn slot(&self) -> u8 {
165 self.desc.index()
166 }
167
168 pub fn register_waiter(&self, uid: usize) -> Result<()> {
172 self.with_bus(|bus| bus.waiter.arm(uid))?
175 .map_err(|e| e.kind)
176 }
177
178 pub fn unregister_waiter(&self) -> Result<()> {
179 self.with_bus(|bus| bus.waiter.disarm())
180 }
181
182 fn with_bus<R, F: FnOnce(&Bus) -> R>(&self, f: F) -> Result<R> {
183 let target_slot = self.desc.index();
184 for cell in SLOTS.iter() {
185 if let Some(bus) = cell.get() {
186 if bus.slot() == target_slot {
187 return Ok(f(bus));
188 }
189 }
190 }
191 Err(PosixError::ENODEV)
192 }
193}
194
195pub fn init() {
196 let _ = LazyLock::force(&BUSES);
197}