Skip to main content

driver_lab_rust/
fuchsia_backends.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Real hardware backends for Fuchsia devices.
6
7use crate::platform_provider::MappedMmio;
8use fidl_fuchsia_hardware_clock as fclock;
9use fidl_fuchsia_hardware_gpio as fgpio;
10use fidl_fuchsia_hardware_i2c as fi2c;
11use fidl_fuchsia_hardware_reset as freset;
12use fidl_fuchsia_hardware_serial as fserial;
13use fidl_fuchsia_hardware_spi as fspi;
14use lab_proxy_core::hardware_backend::BackendError;
15use lab_proxy_core::protocol_resource_adapter::{
16    ClockBackend, GpioBackend, I2cBackend, ResetBackend, ResourceBackend, SerialBackend, SpiBackend,
17};
18use lab_proxy_core::state_bank::StateBank;
19
20/// Volatile GPIO pin backend using synchronous FIDL proxy.
21pub struct FuchsiaGpio {
22    proxy: fgpio::GpioSynchronousProxy,
23}
24
25impl FuchsiaGpio {
26    pub fn new(proxy: fgpio::GpioSynchronousProxy) -> Self {
27        Self { proxy }
28    }
29}
30
31impl std::fmt::Debug for FuchsiaGpio {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        f.debug_struct("FuchsiaGpio").finish()
34    }
35}
36
37impl GpioBackend for FuchsiaGpio {
38    fn read(&mut self) -> Result<bool, BackendError> {
39        match self.proxy.read(zx::MonotonicInstant::INFINITE) {
40            Ok(Ok(val)) => Ok(val),
41            Ok(Err(status)) => {
42                log::warn!("Gpio.read error: {status}");
43                Err(BackendError::Fault)
44            }
45            Err(e) => {
46                log::warn!("Gpio.read fidl error: {e:?}");
47                Err(BackendError::Fault)
48            }
49        }
50    }
51
52    fn write(&mut self, value: bool) -> Result<(), BackendError> {
53        let mode = if value { fgpio::BufferMode::OutputHigh } else { fgpio::BufferMode::OutputLow };
54        match self.proxy.set_buffer_mode(mode, zx::MonotonicInstant::INFINITE) {
55            Ok(Ok(())) => Ok(()),
56            Ok(Err(status)) => {
57                log::warn!("Gpio.set_buffer_mode error: {status}");
58                Err(BackendError::Fault)
59            }
60            Err(e) => {
61                log::warn!("Gpio.set_buffer_mode fidl error: {e:?}");
62                Err(BackendError::Fault)
63            }
64        }
65    }
66}
67
68impl ResourceBackend for FuchsiaGpio {
69    fn gpio_read(&mut self) -> Result<bool, BackendError> {
70        self.read()
71    }
72
73    fn gpio_write(&mut self, value: bool) -> Result<(), BackendError> {
74        self.write(value)
75    }
76}
77
78/// Volatile I2C device backend using synchronous FIDL proxy.
79pub struct FuchsiaI2c {
80    proxy: fi2c::DeviceSynchronousProxy,
81}
82
83impl FuchsiaI2c {
84    pub fn new(proxy: fi2c::DeviceSynchronousProxy) -> Self {
85        Self { proxy }
86    }
87}
88
89impl std::fmt::Debug for FuchsiaI2c {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        f.debug_struct("FuchsiaI2c").finish()
92    }
93}
94
95impl I2cBackend for FuchsiaI2c {
96    fn transfer(&mut self, write_data: &[u8], read_length: usize) -> Result<Vec<u8>, BackendError> {
97        let mut transactions = Vec::new();
98        if !write_data.is_empty() {
99            transactions.push(fi2c::Transaction {
100                data_transfer: Some(fi2c::DataTransfer::WriteData(write_data.to_vec())),
101                stop: Some(read_length == 0),
102                ..Default::default()
103            });
104        }
105        if read_length > 0 {
106            transactions.push(fi2c::Transaction {
107                data_transfer: Some(fi2c::DataTransfer::ReadSize(read_length as u32)),
108                stop: Some(true),
109                ..Default::default()
110            });
111        }
112        if transactions.is_empty() {
113            return Ok(Vec::new());
114        }
115        match self.proxy.transfer(&transactions, zx::MonotonicInstant::INFINITE) {
116            Ok(Ok(mut read_data)) => {
117                if read_length > 0 {
118                    if let Some(data) = read_data.pop() {
119                        return Ok(data);
120                    }
121                    Ok(Vec::new())
122                } else {
123                    Ok(Vec::new())
124                }
125            }
126            Ok(Err(status)) => {
127                log::warn!("I2c.transfer error: {status}");
128                Err(BackendError::Fault)
129            }
130            Err(e) => {
131                log::warn!("I2c.transfer fidl error: {e:?}");
132                Err(BackendError::Fault)
133            }
134        }
135    }
136}
137
138impl ResourceBackend for FuchsiaI2c {
139    fn i2c_transfer(
140        &mut self,
141        write_data: &[u8],
142        read_length: usize,
143    ) -> Result<Vec<u8>, BackendError> {
144        self.transfer(write_data, read_length)
145    }
146}
147
148/// Volatile SPI device backend using synchronous FIDL proxy.
149pub struct FuchsiaSpi {
150    proxy: fspi::DeviceSynchronousProxy,
151}
152
153impl FuchsiaSpi {
154    pub fn new(proxy: fspi::DeviceSynchronousProxy) -> Self {
155        Self { proxy }
156    }
157}
158
159impl std::fmt::Debug for FuchsiaSpi {
160    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161        f.debug_struct("FuchsiaSpi").finish()
162    }
163}
164
165impl SpiBackend for FuchsiaSpi {
166    fn transmit(&mut self, tx_data: &[u8]) -> Result<Vec<u8>, BackendError> {
167        match self.proxy.exchange_vector(tx_data, zx::MonotonicInstant::INFINITE) {
168            Ok((status, rxdata)) => {
169                if status == 0 {
170                    Ok(rxdata)
171                } else {
172                    log::warn!("Spi.exchange_vector error: {status}");
173                    Err(BackendError::Fault)
174                }
175            }
176            Err(e) => {
177                log::warn!("Spi.exchange_vector fidl error: {e:?}");
178                Err(BackendError::Fault)
179            }
180        }
181    }
182}
183
184impl ResourceBackend for FuchsiaSpi {
185    fn spi_transmit(&mut self, tx_data: &[u8]) -> Result<Vec<u8>, BackendError> {
186        self.transmit(tx_data)
187    }
188}
189
190/// Volatile Clock backend using synchronous FIDL proxy.
191pub struct FuchsiaClock {
192    proxy: fclock::ClockSynchronousProxy,
193}
194
195impl FuchsiaClock {
196    pub fn new(proxy: fclock::ClockSynchronousProxy) -> Self {
197        Self { proxy }
198    }
199}
200
201impl std::fmt::Debug for FuchsiaClock {
202    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203        f.debug_struct("FuchsiaClock").finish()
204    }
205}
206
207impl ClockBackend for FuchsiaClock {
208    fn enable(&mut self) -> Result<(), BackendError> {
209        match self.proxy.enable(zx::MonotonicInstant::INFINITE) {
210            Ok(Ok(())) => Ok(()),
211            Ok(Err(status)) => {
212                log::warn!("Clock.enable error: {status}");
213                Err(BackendError::Fault)
214            }
215            Err(e) => {
216                log::warn!("Clock.enable fidl error: {e:?}");
217                Err(BackendError::Fault)
218            }
219        }
220    }
221
222    fn disable(&mut self) -> Result<(), BackendError> {
223        match self.proxy.disable(zx::MonotonicInstant::INFINITE) {
224            Ok(Ok(())) => Ok(()),
225            Ok(Err(status)) => {
226                log::warn!("Clock.disable error: {status}");
227                Err(BackendError::Fault)
228            }
229            Err(e) => {
230                log::warn!("Clock.disable fidl error: {e:?}");
231                Err(BackendError::Fault)
232            }
233        }
234    }
235
236    fn is_enabled(&mut self) -> Result<bool, BackendError> {
237        match self.proxy.is_enabled(zx::MonotonicInstant::INFINITE) {
238            Ok(Ok(val)) => Ok(val),
239            Ok(Err(status)) => {
240                log::warn!("Clock.is_enabled error: {status}");
241                Err(BackendError::Fault)
242            }
243            Err(e) => {
244                log::warn!("Clock.is_enabled fidl error: {e:?}");
245                Err(BackendError::Fault)
246            }
247        }
248    }
249
250    fn set_rate(&mut self, hz: u64) -> Result<(), BackendError> {
251        match self.proxy.set_rate(hz, zx::MonotonicInstant::INFINITE) {
252            Ok(Ok(())) => Ok(()),
253            Ok(Err(status)) => {
254                log::warn!("Clock.set_rate error: {status}");
255                Err(BackendError::Fault)
256            }
257            Err(e) => {
258                log::warn!("Clock.set_rate fidl error: {e:?}");
259                Err(BackendError::Fault)
260            }
261        }
262    }
263
264    fn query_rate(&mut self, hz_in: u64) -> Result<u64, BackendError> {
265        match self.proxy.query_supported_rate(hz_in, zx::MonotonicInstant::INFINITE) {
266            Ok(Ok(val)) => Ok(val),
267            Ok(Err(status)) => {
268                log::warn!("Clock.query_supported_rate error: {status}");
269                Err(BackendError::Fault)
270            }
271            Err(e) => {
272                log::warn!("Clock.query_supported_rate fidl error: {e:?}");
273                Err(BackendError::Fault)
274            }
275        }
276    }
277
278    fn get_rate(&mut self) -> Result<u64, BackendError> {
279        match self.proxy.get_rate(zx::MonotonicInstant::INFINITE) {
280            Ok(Ok(val)) => Ok(val),
281            Ok(Err(status)) => {
282                log::warn!("Clock.get_rate error: {status}");
283                Err(BackendError::Fault)
284            }
285            Err(e) => {
286                log::warn!("Clock.get_rate fidl error: {e:?}");
287                Err(BackendError::Fault)
288            }
289        }
290    }
291}
292
293impl ResourceBackend for FuchsiaClock {
294    fn clock_enable(&mut self) -> Result<(), BackendError> {
295        self.enable()
296    }
297    fn clock_disable(&mut self) -> Result<(), BackendError> {
298        self.disable()
299    }
300    fn clock_is_enabled(&mut self) -> Result<bool, BackendError> {
301        self.is_enabled()
302    }
303    fn clock_set_rate(&mut self, hz: u64) -> Result<(), BackendError> {
304        self.set_rate(hz)
305    }
306    fn clock_query_rate(&mut self, hz_in: u64) -> Result<u64, BackendError> {
307        self.query_rate(hz_in)
308    }
309    fn clock_get_rate(&mut self) -> Result<u64, BackendError> {
310        self.get_rate()
311    }
312}
313
314/// Volatile Reset backend using synchronous FIDL proxy.
315pub struct FuchsiaReset {
316    proxy: freset::ResetSynchronousProxy,
317}
318
319impl FuchsiaReset {
320    pub fn new(proxy: freset::ResetSynchronousProxy) -> Self {
321        Self { proxy }
322    }
323}
324
325impl std::fmt::Debug for FuchsiaReset {
326    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
327        f.debug_struct("FuchsiaReset").finish()
328    }
329}
330
331impl ResetBackend for FuchsiaReset {
332    fn assert(&mut self) -> Result<(), BackendError> {
333        match self.proxy.assert(zx::MonotonicInstant::INFINITE) {
334            Ok(Ok(())) => Ok(()),
335            Ok(Err(status)) => {
336                log::warn!("Reset.assert error: {status}");
337                Err(BackendError::Fault)
338            }
339            Err(e) => {
340                log::warn!("Reset.assert fidl error: {e:?}");
341                Err(BackendError::Fault)
342            }
343        }
344    }
345
346    fn deassert(&mut self) -> Result<(), BackendError> {
347        match self.proxy.deassert(zx::MonotonicInstant::INFINITE) {
348            Ok(Ok(())) => Ok(()),
349            Ok(Err(status)) => {
350                log::warn!("Reset.deassert error: {status}");
351                Err(BackendError::Fault)
352            }
353            Err(e) => {
354                log::warn!("Reset.deassert fidl error: {e:?}");
355                Err(BackendError::Fault)
356            }
357        }
358    }
359
360    fn toggle(&mut self) -> Result<(), BackendError> {
361        match self.proxy.toggle(zx::MonotonicInstant::INFINITE) {
362            Ok(Ok(())) => Ok(()),
363            Ok(Err(status)) => {
364                log::warn!("Reset.toggle error: {status}");
365                Err(BackendError::Fault)
366            }
367            Err(e) => {
368                log::warn!("Reset.toggle fidl error: {e:?}");
369                Err(BackendError::Fault)
370            }
371        }
372    }
373
374    fn status(&mut self) -> Result<bool, BackendError> {
375        match self.proxy.status(zx::MonotonicInstant::INFINITE) {
376            Ok(Ok(val)) => Ok(val),
377            Ok(Err(status)) => {
378                log::warn!("Reset.status error: {status}");
379                Err(BackendError::Fault)
380            }
381            Err(e) => {
382                log::warn!("Reset.status fidl error: {e:?}");
383                Err(BackendError::Fault)
384            }
385        }
386    }
387}
388
389impl ResourceBackend for FuchsiaReset {
390    fn reset_assert(&mut self) -> Result<(), BackendError> {
391        self.assert()
392    }
393    fn reset_deassert(&mut self) -> Result<(), BackendError> {
394        self.deassert()
395    }
396    fn reset_toggle(&mut self) -> Result<(), BackendError> {
397        self.toggle()
398    }
399    fn reset_status(&mut self) -> Result<bool, BackendError> {
400        self.status()
401    }
402}
403
404/// Volatile Serial backend using synchronous FIDL proxy.
405pub struct FuchsiaSerial {
406    proxy: fserial::DeviceSynchronousProxy,
407}
408
409impl FuchsiaSerial {
410    pub fn new(proxy: fserial::DeviceSynchronousProxy) -> Self {
411        Self { proxy }
412    }
413}
414
415impl std::fmt::Debug for FuchsiaSerial {
416    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
417        f.debug_struct("FuchsiaSerial").finish()
418    }
419}
420
421impl SerialBackend for FuchsiaSerial {
422    fn read(&mut self) -> Result<Vec<u8>, BackendError> {
423        match self.proxy.read(zx::MonotonicInstant::INFINITE) {
424            Ok(Ok(val)) => Ok(val),
425            Ok(Err(status)) => {
426                log::warn!("Serial.read error: {status}");
427                Err(BackendError::Fault)
428            }
429            Err(e) => {
430                log::warn!("Serial.read fidl error: {e:?}");
431                Err(BackendError::Fault)
432            }
433        }
434    }
435
436    fn write(&mut self, data: &[u8]) -> Result<(), BackendError> {
437        match self.proxy.write(data, zx::MonotonicInstant::INFINITE) {
438            Ok(Ok(())) => Ok(()),
439            Ok(Err(status)) => {
440                log::warn!("Serial.write error: {status}");
441                Err(BackendError::Fault)
442            }
443            Err(e) => {
444                log::warn!("Serial.write fidl error: {e:?}");
445                Err(BackendError::Fault)
446            }
447        }
448    }
449}
450
451impl ResourceBackend for FuchsiaSerial {
452    fn serial_read(&mut self) -> Result<Vec<u8>, BackendError> {
453        self.read()
454    }
455    fn serial_write(&mut self, data: &[u8]) -> Result<(), BackendError> {
456        self.write(data)
457    }
458}
459
460/// Heterogeneous live hardware backend covering MMIO, software state banks, GPIO, I2C, SPI, Clock, Reset, Serial, and Interrupts.
461#[derive(Debug)]
462pub enum LiveBackend {
463    Mmio(MappedMmio),
464    State(StateBank),
465    Gpio(FuchsiaGpio),
466    I2c(FuchsiaI2c),
467    Spi(FuchsiaSpi),
468    Clock(FuchsiaClock),
469    Reset(FuchsiaReset),
470    Serial(FuchsiaSerial),
471    Interrupt,
472}
473
474impl ResourceBackend for LiveBackend {
475    fn read32(&mut self, offset: u64) -> Result<u32, BackendError> {
476        match self {
477            Self::Mmio(m) => m.read32(offset),
478            Self::State(s) => s.read32(offset),
479            _ => Err(BackendError::Fault),
480        }
481    }
482
483    fn write32(&mut self, offset: u64, value: u32) -> Result<(), BackendError> {
484        match self {
485            Self::Mmio(m) => m.write32(offset, value),
486            Self::State(s) => s.write32(offset, value),
487            _ => Err(BackendError::Fault),
488        }
489    }
490
491    fn barrier(&mut self) {
492        match self {
493            Self::Mmio(m) => m.barrier(),
494            Self::State(s) => s.barrier(),
495            _ => {}
496        }
497    }
498
499    fn gpio_read(&mut self) -> Result<bool, BackendError> {
500        match self {
501            Self::Gpio(g) => g.gpio_read(),
502            _ => Err(BackendError::Fault),
503        }
504    }
505
506    fn gpio_write(&mut self, value: bool) -> Result<(), BackendError> {
507        match self {
508            Self::Gpio(g) => g.gpio_write(value),
509            _ => Err(BackendError::Fault),
510        }
511    }
512
513    fn i2c_transfer(
514        &mut self,
515        write_data: &[u8],
516        read_length: usize,
517    ) -> Result<Vec<u8>, BackendError> {
518        match self {
519            Self::I2c(i) => i.i2c_transfer(write_data, read_length),
520            _ => Err(BackendError::Fault),
521        }
522    }
523
524    fn spi_transmit(&mut self, tx_data: &[u8]) -> Result<Vec<u8>, BackendError> {
525        match self {
526            Self::Spi(s) => s.spi_transmit(tx_data),
527            _ => Err(BackendError::Fault),
528        }
529    }
530
531    fn clock_enable(&mut self) -> Result<(), BackendError> {
532        match self {
533            Self::Clock(c) => c.clock_enable(),
534            _ => Err(BackendError::Fault),
535        }
536    }
537
538    fn clock_disable(&mut self) -> Result<(), BackendError> {
539        match self {
540            Self::Clock(c) => c.clock_disable(),
541            _ => Err(BackendError::Fault),
542        }
543    }
544
545    fn clock_is_enabled(&mut self) -> Result<bool, BackendError> {
546        match self {
547            Self::Clock(c) => c.clock_is_enabled(),
548            _ => Err(BackendError::Fault),
549        }
550    }
551
552    fn clock_set_rate(&mut self, hz: u64) -> Result<(), BackendError> {
553        match self {
554            Self::Clock(c) => c.clock_set_rate(hz),
555            _ => Err(BackendError::Fault),
556        }
557    }
558
559    fn clock_query_rate(&mut self, hz_in: u64) -> Result<u64, BackendError> {
560        match self {
561            Self::Clock(c) => c.clock_query_rate(hz_in),
562            _ => Err(BackendError::Fault),
563        }
564    }
565
566    fn clock_get_rate(&mut self) -> Result<u64, BackendError> {
567        match self {
568            Self::Clock(c) => c.clock_get_rate(),
569            _ => Err(BackendError::Fault),
570        }
571    }
572
573    fn reset_assert(&mut self) -> Result<(), BackendError> {
574        match self {
575            Self::Reset(r) => r.reset_assert(),
576            _ => Err(BackendError::Fault),
577        }
578    }
579
580    fn reset_deassert(&mut self) -> Result<(), BackendError> {
581        match self {
582            Self::Reset(r) => r.reset_deassert(),
583            _ => Err(BackendError::Fault),
584        }
585    }
586
587    fn reset_toggle(&mut self) -> Result<(), BackendError> {
588        match self {
589            Self::Reset(r) => r.reset_toggle(),
590            _ => Err(BackendError::Fault),
591        }
592    }
593
594    fn reset_status(&mut self) -> Result<bool, BackendError> {
595        match self {
596            Self::Reset(r) => r.reset_status(),
597            _ => Err(BackendError::Fault),
598        }
599    }
600
601    fn serial_read(&mut self) -> Result<Vec<u8>, BackendError> {
602        match self {
603            Self::Serial(s) => s.serial_read(),
604            _ => Err(BackendError::Fault),
605        }
606    }
607
608    fn serial_write(&mut self, data: &[u8]) -> Result<(), BackendError> {
609        match self {
610            Self::Serial(s) => s.serial_write(data),
611            _ => Err(BackendError::Fault),
612        }
613    }
614}