Skip to content

Commit 595dfc8

Browse files
committed
zephyr: Make gpio interface much more "unsafe"
Gpios in Zephyr are inherently unsafe. There is a shared controller that is not just used by the pins defined here, but extensively across various drivers. As such, make all of the gpio pin operations themselves unsafe. We can help, a little bit, to at least enforce uniqueness with the Rust drivers that use gpios by requiring them to take a mutable instance of `GpioToken`, which has a singleton getter. Signed-off-by: David Brown <[email protected]>
1 parent baa5dc1 commit 595dfc8

File tree

1 file changed

+33
-4
lines changed

1 file changed

+33
-4
lines changed

zephyr/src/device.rs

+33-4
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,36 @@ pub mod gpio {
4141
//! devices. We want to have stronger typing in the Zephyr interfaces, so most of these types
4242
//! will be wrapped in another structure. This wraps a Gpio device, and provides methods to
4343
//! 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.
4448
4549
use crate::raw;
4650
use super::Unique;
4751

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+
4874
/// A single instance of a zephyr device to manage a gpio controller. A gpio controller
4975
/// represents a set of gpio pins, that are generally operated on by the same hardware block.
5076
pub struct Gpio {
@@ -73,8 +99,11 @@ pub mod gpio {
7399
}
74100
}
75101

76-
/// A GpioPin represents a single pin on a gpio device. This is a lightweight wrapper around
77-
/// the Zephyr `gpio_dt_spec` structure.
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`].
78107
#[allow(dead_code)]
79108
pub struct GpioPin {
80109
pub(crate) pin: raw::gpio_dt_spec,
@@ -111,7 +140,7 @@ pub mod gpio {
111140
}
112141

113142
/// Configure a single pin.
114-
pub fn configure(&mut self, extra_flags: raw::gpio_flags_t) {
143+
pub unsafe fn configure(&mut self, _token: &mut GpioToken, extra_flags: raw::gpio_flags_t) {
115144
// TODO: Error?
116145
unsafe {
117146
raw::gpio_pin_configure(self.pin.port,
@@ -121,7 +150,7 @@ pub mod gpio {
121150
}
122151

123152
/// Toggle pin level.
124-
pub fn toggle_pin(&mut self) {
153+
pub unsafe fn toggle_pin(&mut self, _token: &mut GpioToken) {
125154
// TODO: Error?
126155
unsafe {
127156
raw::gpio_pin_toggle_dt(&self.pin);

0 commit comments

Comments
 (0)