Skip to content

Commit d4754e1

Browse files
committed
zephyr: device: Split gpio and flash to own files
Move this code out of the device.rs file, and into separate files for each module. Signed-off-by: David Brown <[email protected]>
1 parent b8d2f82 commit d4754e1

File tree

3 files changed

+180
-183
lines changed

3 files changed

+180
-183
lines changed

zephyr/src/device.rs

+3-183
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
88
use crate::sync::atomic::{AtomicUsize, Ordering};
99

10+
pub mod gpio;
11+
pub mod flash;
12+
1013
// Allow dead code, because it isn't required for a given build to have any devices.
1114
/// Device uniqueness.
1215
///
@@ -35,186 +38,3 @@ impl Unique {
3538
self.0.fetch_add(1, Ordering::AcqRel) == 0
3639
}
3740
}
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-
//! Safey: In general, even just using gpio pins is unsafe in Zephyr. The gpio drivers are used
46-
//! pervasively throughout Zephyr device drivers. As such, most of the calls in this module are
47-
//! unsafe.
48-
49-
use crate::raw;
50-
use super::Unique;
51-
52-
/// Global instance to help make gpio in Rust slightly safer.
53-
///
54-
/// To help with safety, the rust types use a global instance of a gpio-token. Methods will
55-
/// take a mutable reference to this, which will require either a single thread in the
56-
/// application code, or something like a mutex or critical section to manage. The operation
57-
/// methods are still unsafe, because we have no control over what happens with the gpio
58-
/// operations outside of Rust code, but this will help make the Rust usage at least better.
59-
pub struct GpioToken(());
60-
61-
static GPIO_TOKEN: Unique = Unique::new();
62-
63-
impl GpioToken {
64-
/// Retrieves the gpio token. This is unsafe because lots of code in zephyr operates on the
65-
/// gpio drivers.
66-
pub unsafe fn get_instance() -> Option<GpioToken> {
67-
if !GPIO_TOKEN.once() {
68-
return None;
69-
}
70-
Some(GpioToken(()))
71-
}
72-
}
73-
74-
/// A single instance of a zephyr device to manage a gpio controller. A gpio controller
75-
/// represents a set of gpio pins, that are generally operated on by the same hardware block.
76-
pub struct Gpio {
77-
/// The underlying device itself.
78-
#[allow(dead_code)]
79-
pub(crate) device: *const raw::device,
80-
}
81-
82-
impl Gpio {
83-
/// Constructor, used by the devicetree generated code.
84-
///
85-
/// TODO: Guarantee single instancing.
86-
pub(crate) unsafe fn new(unique: &Unique, device: *const raw::device) -> Option<Gpio> {
87-
if !unique.once() {
88-
return None;
89-
}
90-
Some(Gpio { device })
91-
}
92-
93-
/// Verify that the device is ready for use. At a minimum, this means the device has been
94-
/// successfully initialized.
95-
pub fn is_ready(&self) -> bool {
96-
unsafe {
97-
raw::device_is_ready(self.device)
98-
}
99-
}
100-
}
101-
102-
/// A GpioPin represents a single pin on a gpio device.
103-
///
104-
/// This is a lightweight wrapper around the Zephyr `gpio_dt_spec` structure. Note that
105-
/// multiple pins may share a gpio controller, and as such, all methods on this are both unsafe,
106-
/// and require a mutable reference to the [`GpioToken`].
107-
#[allow(dead_code)]
108-
pub struct GpioPin {
109-
pub(crate) pin: raw::gpio_dt_spec,
110-
}
111-
112-
impl GpioPin {
113-
/// Constructor, used by the devicetree generated code.
114-
///
115-
/// TODO: Guarantee single instancing.
116-
pub(crate) unsafe fn new(unique: &Unique, device: *const raw::device, pin: u32, dt_flags: u32) -> Option<GpioPin> {
117-
if !unique.once() {
118-
return None;
119-
}
120-
Some(GpioPin {
121-
pin: raw::gpio_dt_spec {
122-
port: device,
123-
pin: pin as raw::gpio_pin_t,
124-
dt_flags: dt_flags as raw::gpio_dt_flags_t,
125-
}
126-
})
127-
}
128-
129-
/// Verify that the device is ready for use. At a minimum, this means the device has been
130-
/// successfully initialized.
131-
pub fn is_ready(&self) -> bool {
132-
self.get_gpio().is_ready()
133-
}
134-
135-
/// Get the underlying Gpio device.
136-
pub fn get_gpio(&self) -> Gpio {
137-
Gpio {
138-
device: self.pin.port,
139-
}
140-
}
141-
142-
/// Configure a single pin.
143-
pub unsafe fn configure(&mut self, _token: &mut GpioToken, extra_flags: raw::gpio_flags_t) {
144-
// TODO: Error?
145-
unsafe {
146-
raw::gpio_pin_configure(self.pin.port,
147-
self.pin.pin,
148-
self.pin.dt_flags as raw::gpio_flags_t | extra_flags);
149-
}
150-
}
151-
152-
/// Toggle pin level.
153-
pub unsafe fn toggle_pin(&mut self, _token: &mut GpioToken) {
154-
// TODO: Error?
155-
unsafe {
156-
raw::gpio_pin_toggle_dt(&self.pin);
157-
}
158-
}
159-
}
160-
}
161-
162-
pub mod flash {
163-
//! Device wrappers for flash controllers, and flash partitions.
164-
165-
use crate::raw;
166-
use super::Unique;
167-
168-
/// A flash controller
169-
///
170-
/// This is a wrapper around the `struct device` in Zephyr that represents a flash controller.
171-
/// Using the flash controller allows flash operations on the entire device. See
172-
/// [`FlashPartition`] for a wrapper that limits the operation to a partition as defined in the
173-
/// DT.
174-
#[allow(dead_code)]
175-
pub struct FlashController {
176-
pub(crate) device: *const raw::device,
177-
}
178-
179-
impl FlashController {
180-
/// Constructor, intended to be called by devicetree generated code.
181-
pub(crate) unsafe fn new(unique: &Unique, device: *const raw::device) -> Option<FlashController> {
182-
if !unique.once() {
183-
return None;
184-
}
185-
186-
Some(FlashController { device })
187-
}
188-
}
189-
190-
/// A wrapper for flash partitions. There is no Zephyr struct that corresponds with this
191-
/// information, which is typically used in a more direct underlying manner.
192-
#[allow(dead_code)]
193-
pub struct FlashPartition {
194-
/// The underlying controller.
195-
#[allow(dead_code)]
196-
pub(crate) controller: FlashController,
197-
#[allow(dead_code)]
198-
pub(crate) offset: u32,
199-
#[allow(dead_code)]
200-
pub(crate) size: u32,
201-
}
202-
203-
impl FlashPartition {
204-
/// Constructor, intended to be called by devicetree generated code.
205-
pub(crate) unsafe fn new(unique: &Unique, device: *const raw::device, offset: u32, size: u32) -> Option<FlashPartition> {
206-
if !unique.once() {
207-
return None;
208-
}
209-
210-
// The `get_instance` on the flash controller would try to guarantee a unique instance,
211-
// but in this case, we need one for each device, so just construct it here.
212-
// TODO: This is not actually safe.
213-
let controller = FlashController { device };
214-
Some(FlashPartition { controller, offset, size })
215-
}
216-
}
217-
218-
// Note that currently, the flash partition shares the controller, so the underlying operations
219-
// are not actually safe. Need to rethink how to manage this.
220-
}

zephyr/src/device/flash.rs

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//! Device wrappers for flash controllers, and flash partitions.
2+
3+
use crate::raw;
4+
use super::Unique;
5+
6+
/// A flash controller
7+
///
8+
/// This is a wrapper around the `struct device` in Zephyr that represents a flash controller.
9+
/// Using the flash controller allows flash operations on the entire device. See
10+
/// [`FlashPartition`] for a wrapper that limits the operation to a partition as defined in the
11+
/// DT.
12+
#[allow(dead_code)]
13+
pub struct FlashController {
14+
pub(crate) device: *const raw::device,
15+
}
16+
17+
impl FlashController {
18+
/// Constructor, intended to be called by devicetree generated code.
19+
pub(crate) unsafe fn new(unique: &Unique, device: *const raw::device) -> Option<FlashController> {
20+
if !unique.once() {
21+
return None;
22+
}
23+
24+
Some(FlashController { device })
25+
}
26+
}
27+
28+
/// A wrapper for flash partitions. There is no Zephyr struct that corresponds with this
29+
/// information, which is typically used in a more direct underlying manner.
30+
#[allow(dead_code)]
31+
pub struct FlashPartition {
32+
/// The underlying controller.
33+
#[allow(dead_code)]
34+
pub(crate) controller: FlashController,
35+
#[allow(dead_code)]
36+
pub(crate) offset: u32,
37+
#[allow(dead_code)]
38+
pub(crate) size: u32,
39+
}
40+
41+
impl FlashPartition {
42+
/// Constructor, intended to be called by devicetree generated code.
43+
pub(crate) unsafe fn new(unique: &Unique, device: *const raw::device, offset: u32, size: u32) -> Option<FlashPartition> {
44+
if !unique.once() {
45+
return None;
46+
}
47+
48+
// The `get_instance` on the flash controller would try to guarantee a unique instance,
49+
// but in this case, we need one for each device, so just construct it here.
50+
// TODO: This is not actually safe.
51+
let controller = FlashController { device };
52+
Some(FlashPartition { controller, offset, size })
53+
}
54+
}
55+
56+
// Note that currently, the flash partition shares the controller, so the underlying operations
57+
// are not actually safe. Need to rethink how to manage this.

zephyr/src/device/gpio.rs

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//! Most devices in Zephyr operate on a `struct device`. This provides untyped access to
2+
//! devices. We want to have stronger typing in the Zephyr interfaces, so most of these types
3+
//! will be wrapped in another structure. This wraps a Gpio device, and provides methods to
4+
//! most of the operations on gpios.
5+
//!
6+
//! Safey: In general, even just using gpio pins is unsafe in Zephyr. The gpio drivers are used
7+
//! pervasively throughout Zephyr device drivers. As such, most of the calls in this module are
8+
//! unsafe.
9+
10+
use crate::raw;
11+
use super::Unique;
12+
13+
/// Global instance to help make gpio in Rust slightly safer.
14+
///
15+
/// To help with safety, the rust types use a global instance of a gpio-token. Methods will
16+
/// take a mutable reference to this, which will require either a single thread in the
17+
/// application code, or something like a mutex or critical section to manage. The operation
18+
/// methods are still unsafe, because we have no control over what happens with the gpio
19+
/// operations outside of Rust code, but this will help make the Rust usage at least better.
20+
pub struct GpioToken(());
21+
22+
static GPIO_TOKEN: Unique = Unique::new();
23+
24+
impl GpioToken {
25+
/// Retrieves the gpio token. This is unsafe because lots of code in zephyr operates on the
26+
/// gpio drivers.
27+
pub unsafe fn get_instance() -> Option<GpioToken> {
28+
if !GPIO_TOKEN.once() {
29+
return None;
30+
}
31+
Some(GpioToken(()))
32+
}
33+
}
34+
35+
/// A single instance of a zephyr device to manage a gpio controller. A gpio controller
36+
/// represents a set of gpio pins, that are generally operated on by the same hardware block.
37+
pub struct Gpio {
38+
/// The underlying device itself.
39+
#[allow(dead_code)]
40+
pub(crate) device: *const raw::device,
41+
}
42+
43+
impl Gpio {
44+
/// Constructor, used by the devicetree generated code.
45+
///
46+
/// TODO: Guarantee single instancing.
47+
pub(crate) unsafe fn new(unique: &Unique, device: *const raw::device) -> Option<Gpio> {
48+
if !unique.once() {
49+
return None;
50+
}
51+
Some(Gpio { device })
52+
}
53+
54+
/// Verify that the device is ready for use. At a minimum, this means the device has been
55+
/// successfully initialized.
56+
pub fn is_ready(&self) -> bool {
57+
unsafe {
58+
raw::device_is_ready(self.device)
59+
}
60+
}
61+
}
62+
63+
/// A GpioPin represents a single pin on a gpio device.
64+
///
65+
/// This is a lightweight wrapper around the Zephyr `gpio_dt_spec` structure. Note that
66+
/// multiple pins may share a gpio controller, and as such, all methods on this are both unsafe,
67+
/// and require a mutable reference to the [`GpioToken`].
68+
#[allow(dead_code)]
69+
pub struct GpioPin {
70+
pub(crate) pin: raw::gpio_dt_spec,
71+
}
72+
73+
impl GpioPin {
74+
/// Constructor, used by the devicetree generated code.
75+
///
76+
/// TODO: Guarantee single instancing.
77+
pub(crate) unsafe fn new(unique: &Unique, device: *const raw::device, pin: u32, dt_flags: u32) -> Option<GpioPin> {
78+
if !unique.once() {
79+
return None;
80+
}
81+
Some(GpioPin {
82+
pin: raw::gpio_dt_spec {
83+
port: device,
84+
pin: pin as raw::gpio_pin_t,
85+
dt_flags: dt_flags as raw::gpio_dt_flags_t,
86+
}
87+
})
88+
}
89+
90+
/// Verify that the device is ready for use. At a minimum, this means the device has been
91+
/// successfully initialized.
92+
pub fn is_ready(&self) -> bool {
93+
self.get_gpio().is_ready()
94+
}
95+
96+
/// Get the underlying Gpio device.
97+
pub fn get_gpio(&self) -> Gpio {
98+
Gpio {
99+
device: self.pin.port,
100+
}
101+
}
102+
103+
/// Configure a single pin.
104+
pub unsafe fn configure(&mut self, _token: &mut GpioToken, extra_flags: raw::gpio_flags_t) {
105+
// TODO: Error?
106+
unsafe {
107+
raw::gpio_pin_configure(self.pin.port,
108+
self.pin.pin,
109+
self.pin.dt_flags as raw::gpio_flags_t | extra_flags);
110+
}
111+
}
112+
113+
/// Toggle pin level.
114+
pub unsafe fn toggle_pin(&mut self, _token: &mut GpioToken) {
115+
// TODO: Error?
116+
unsafe {
117+
raw::gpio_pin_toggle_dt(&self.pin);
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)