Skip to content

Commit baa5dc1

Browse files
committed
zephyr: Enforce uniqueness on device tree wrappers
Move all of the device implementations into a `zephyr::device` module. In this module, add a `Unique` type that supports the constructors on the device requiring a unique instance. The device tree augmentation code adds a declaration for these uniqueness markers for each instance, passing it into the constructor. Signed-off-by: David Brown <[email protected]>
1 parent 0133bd8 commit baa5dc1

File tree

6 files changed

+207
-147
lines changed

6 files changed

+207
-147
lines changed

dt-rust.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
value:
1515
raw:
1616
type: myself
17-
device: crate::sys::gpio::Gpio
17+
device: crate::device::gpio::Gpio
1818

1919
# The gpio-leds node will have #children nodes describing each led. We'll match on the parent
2020
# having this compatible property. The nodes themselves are built out of the properties associated
@@ -32,7 +32,7 @@
3232
raw:
3333
type: phandle
3434
value: gpios
35-
device: crate::sys::gpio::GpioPin
35+
device: crate::device::gpio::GpioPin
3636

3737
# Flash controllers don't have any particular property to identify them, so we need a list of
3838
# compatible values that should match.
@@ -49,7 +49,7 @@
4949
value:
5050
raw:
5151
type: myself
52-
device: crate::sys::flash::FlashController
52+
device: crate::device::flash::FlashController
5353

5454
# Flash partitions exist as children of a node compatible with "soc-nv-flash" that itself is a child
5555
# of the controller itself.
@@ -75,7 +75,7 @@
7575
level: 3
7676
args:
7777
- type: reg
78-
device: "crate::sys::flash::FlashPartition"
78+
device: "crate::device::flash::FlashPartition"
7979

8080
# Generate a pseudo node that matches all of the labels across the tree with their nodes.
8181
- name: labels

samples/blinky/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ extern "C" fn rust_main() {
3939
unsafe extern "C" fn blink(_p1: *mut c_void, _p2: *mut c_void, _p3: *mut c_void) {
4040
warn!("Inside of blinky");
4141

42-
let mut led0 = zephyr::devicetree::aliases::led0::get_instance();
42+
let mut led0 = zephyr::devicetree::aliases::led0::get_instance().unwrap();
4343

4444
if !led0.is_ready() {
4545
warn!("LED is not ready");

zephyr-build/src/devicetree/config.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,12 @@ impl RawInfo {
177177
pub unsafe fn get_instance_raw() -> *const crate::raw::device {
178178
&crate::raw::#rawdev
179179
}
180-
pub fn get_instance() -> #device_id {
180+
181+
static UNIQUE: crate::device::Unique = crate::device::Unique::new();
182+
pub fn get_instance() -> Option<#device_id> {
181183
unsafe {
182184
let device = get_instance_raw();
183-
#device_id::new(device)
185+
#device_id::new(&UNIQUE, device)
184186
}
185187
}
186188
}
@@ -202,10 +204,11 @@ impl RawInfo {
202204
let target_route = target.route_to_rust();
203205

204206
quote! {
205-
pub fn get_instance() -> #device_id {
207+
static UNIQUE: crate::device::Unique = crate::device::Unique::new();
208+
pub fn get_instance() -> Option<#device_id> {
206209
unsafe {
207210
let device = #target_route :: get_instance_raw();
208-
#device_id::new(device, #(#args),*)
211+
#device_id::new(&UNIQUE, device, #(#args),*)
209212
}
210213
}
211214
}
@@ -220,10 +223,11 @@ impl RawInfo {
220223
}
221224

222225
quote! {
223-
pub fn get_instance() -> #device_id {
226+
static UNIQUE: crate::device::Unique = crate::device::Unique::new();
227+
pub fn get_instance() -> Option<#device_id> {
224228
unsafe {
225229
let device = #path :: get_instance_raw();
226-
#device_id::new(device, #(#get_args),*)
230+
#device_id::new(&UNIQUE, device, #(#get_args),*)
227231
}
228232
}
229233
}

zephyr/src/device.rs

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
//! Device wrappers
2+
//!
3+
//! This module contains implementations of wrappers for various types of devices in zephyr. In
4+
//! general, these wrap a `*const device` from Zephyr, and provide an API that is appropriate.
5+
//!
6+
//! Most of these instances come from the device tree.
7+
8+
use crate::sync::atomic::{AtomicUsize, Ordering};
9+
10+
// Allow dead code, because it isn't required for a given build to have any devices.
11+
/// Device uniqueness.
12+
///
13+
/// As the zephyr devices are statically defined structures, this `Unique` value ensures that the
14+
/// user is only able to get a single instance of any given device.
15+
///
16+
/// Note that some devices in zephyr will require more than one instance of the actual device. For
17+
/// example, a [`GpioPin`] will reference a single pin, but the underlying device for the gpio
18+
/// driver will be shared among then. Generally, the constructor for the individual device will
19+
/// call `get_instance_raw()` on the underlying device.
20+
#[allow(dead_code)]
21+
pub(crate) struct Unique(pub(crate) AtomicUsize);
22+
23+
impl Unique {
24+
/// Construct a new unique counter.
25+
pub(crate) const fn new() -> Unique {
26+
Unique(AtomicUsize::new(0))
27+
}
28+
29+
/// Indicates if this particular entity can be used. This function, on a given `Unique` value
30+
/// will return true exactly once.
31+
#[allow(dead_code)]
32+
pub(crate) fn once(&self) -> bool {
33+
// `fetch_add` is likely to be faster than compare_exchage. This does have the limitation
34+
// that `once` is not called more than `usize::MAX` times.
35+
self.0.fetch_add(1, Ordering::AcqRel) == 0
36+
}
37+
}
38+
39+
pub mod gpio {
40+
//! Most devices in Zephyr operate on a `struct device`. This provides untyped access to
41+
//! devices. We want to have stronger typing in the Zephyr interfaces, so most of these types
42+
//! will be wrapped in another structure. This wraps a Gpio device, and provides methods to
43+
//! most of the operations on gpios.
44+
45+
use crate::raw;
46+
use super::Unique;
47+
48+
/// A single instance of a zephyr device to manage a gpio controller. A gpio controller
49+
/// represents a set of gpio pins, that are generally operated on by the same hardware block.
50+
pub struct Gpio {
51+
/// The underlying device itself.
52+
#[allow(dead_code)]
53+
pub(crate) device: *const raw::device,
54+
}
55+
56+
impl Gpio {
57+
/// Constructor, used by the devicetree generated code.
58+
///
59+
/// TODO: Guarantee single instancing.
60+
pub(crate) unsafe fn new(unique: &Unique, device: *const raw::device) -> Option<Gpio> {
61+
if !unique.once() {
62+
return None;
63+
}
64+
Some(Gpio { device })
65+
}
66+
67+
/// Verify that the device is ready for use. At a minimum, this means the device has been
68+
/// successfully initialized.
69+
pub fn is_ready(&self) -> bool {
70+
unsafe {
71+
raw::device_is_ready(self.device)
72+
}
73+
}
74+
}
75+
76+
/// A GpioPin represents a single pin on a gpio device. This is a lightweight wrapper around
77+
/// the Zephyr `gpio_dt_spec` structure.
78+
#[allow(dead_code)]
79+
pub struct GpioPin {
80+
pub(crate) pin: raw::gpio_dt_spec,
81+
}
82+
83+
impl GpioPin {
84+
/// Constructor, used by the devicetree generated code.
85+
///
86+
/// TODO: Guarantee single instancing.
87+
pub(crate) unsafe fn new(unique: &Unique, device: *const raw::device, pin: u32, dt_flags: u32) -> Option<GpioPin> {
88+
if !unique.once() {
89+
return None;
90+
}
91+
Some(GpioPin {
92+
pin: raw::gpio_dt_spec {
93+
port: device,
94+
pin: pin as raw::gpio_pin_t,
95+
dt_flags: dt_flags as raw::gpio_dt_flags_t,
96+
}
97+
})
98+
}
99+
100+
/// Verify that the device is ready for use. At a minimum, this means the device has been
101+
/// successfully initialized.
102+
pub fn is_ready(&self) -> bool {
103+
self.get_gpio().is_ready()
104+
}
105+
106+
/// Get the underlying Gpio device.
107+
pub fn get_gpio(&self) -> Gpio {
108+
Gpio {
109+
device: self.pin.port,
110+
}
111+
}
112+
113+
/// Configure a single pin.
114+
pub fn configure(&mut self, extra_flags: raw::gpio_flags_t) {
115+
// TODO: Error?
116+
unsafe {
117+
raw::gpio_pin_configure(self.pin.port,
118+
self.pin.pin,
119+
self.pin.dt_flags as raw::gpio_flags_t | extra_flags);
120+
}
121+
}
122+
123+
/// Toggle pin level.
124+
pub fn toggle_pin(&mut self) {
125+
// TODO: Error?
126+
unsafe {
127+
raw::gpio_pin_toggle_dt(&self.pin);
128+
}
129+
}
130+
}
131+
}
132+
133+
pub mod flash {
134+
//! Device wrappers for flash controllers, and flash partitions.
135+
136+
use crate::raw;
137+
use super::Unique;
138+
139+
/// A flash controller
140+
///
141+
/// This is a wrapper around the `struct device` in Zephyr that represents a flash controller.
142+
/// Using the flash controller allows flash operations on the entire device. See
143+
/// [`FlashPartition`] for a wrapper that limits the operation to a partition as defined in the
144+
/// DT.
145+
#[allow(dead_code)]
146+
pub struct FlashController {
147+
pub(crate) device: *const raw::device,
148+
}
149+
150+
impl FlashController {
151+
/// Constructor, intended to be called by devicetree generated code.
152+
pub(crate) unsafe fn new(unique: &Unique, device: *const raw::device) -> Option<FlashController> {
153+
if !unique.once() {
154+
return None;
155+
}
156+
157+
Some(FlashController { device })
158+
}
159+
}
160+
161+
/// A wrapper for flash partitions. There is no Zephyr struct that corresponds with this
162+
/// information, which is typically used in a more direct underlying manner.
163+
#[allow(dead_code)]
164+
pub struct FlashPartition {
165+
/// The underlying controller.
166+
#[allow(dead_code)]
167+
pub(crate) controller: FlashController,
168+
#[allow(dead_code)]
169+
pub(crate) offset: u32,
170+
#[allow(dead_code)]
171+
pub(crate) size: u32,
172+
}
173+
174+
impl FlashPartition {
175+
/// Constructor, intended to be called by devicetree generated code.
176+
pub(crate) unsafe fn new(unique: &Unique, device: *const raw::device, offset: u32, size: u32) -> Option<FlashPartition> {
177+
if !unique.once() {
178+
return None;
179+
}
180+
181+
// The `get_instance` on the flash controller would try to guarantee a unique instance,
182+
// but in this case, we need one for each device, so just construct it here.
183+
// TODO: This is not actually safe.
184+
let controller = FlashController { device };
185+
Some(FlashPartition { controller, offset, size })
186+
}
187+
}
188+
189+
// Note that currently, the flash partition shares the controller, so the underlying operations
190+
// are not actually safe. Need to rethink how to manage this.
191+
}

zephyr/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#![deny(missing_docs)]
1212

1313
pub mod align;
14+
pub mod device;
1415
pub mod error;
1516
pub mod object;
1617
pub mod sync;

0 commit comments

Comments
 (0)