Skip to content

Commit e4058af

Browse files
committed
zephyr: device: Add uart
Add a simplistic uart wrapper, and drivers around it. Signed-off-by: David Brown <[email protected]>
1 parent 54c6ac5 commit e4058af

File tree

6 files changed

+148
-3
lines changed

6 files changed

+148
-3
lines changed

dt-rust.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,26 @@
7777
- type: reg
7878
device: "crate::device::flash::FlashPartition"
7979

80+
# Uart devices. This just has to be a list of devices that implement this interface.
81+
- name: uart
82+
rules:
83+
- type: compatible
84+
value:
85+
names:
86+
- "arm,pl011"
87+
# The nordic driver needs to be separate because they have a separate Kconfig for each uart
88+
# block.
89+
# - "nordic,nrf-uarte"
90+
- "zephyr,cdc-acm-uart"
91+
level: 0
92+
actions:
93+
- type: instance
94+
value:
95+
raw:
96+
type: myself
97+
device: "crate::device::uart::Uart"
98+
kconfig: CONFIG_SERIAL
99+
80100
# Generate a pseudo node that matches all of the labels across the tree with their nodes.
81101
- name: labels
82102
rules:

zephyr-build/src/devicetree/augment.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ pub trait Augment {
2828
/// The default implementation checks if this node matches and calls a generator if it does, or
2929
/// does nothing if not.
3030
fn augment(&self, node: &Node, tree: &DeviceTree) -> TokenStream {
31+
// If there is a status field present, and it is not set to "okay", don't augment this node.
32+
if let Some(status) = node.get_single_string("status") {
33+
if status != "okay" {
34+
return TokenStream::new();
35+
}
36+
}
3137
if self.is_compatible(node) {
3238
self.generate(node, tree)
3339
} else {
@@ -135,6 +141,9 @@ pub enum Action {
135141
/// The name of the full path (within the zephyr-sys crate) for the wrapper node for this
136142
/// device.
137143
device: String,
144+
/// A Kconfig option to allow the instances to only be present when said driver is compiled
145+
/// in.
146+
kconfig: Option<String>,
138147
},
139148
/// Generate all of the labels as its own node.
140149
Labels,
@@ -143,8 +152,8 @@ pub enum Action {
143152
impl Action {
144153
fn generate(&self, _name: &Ident, node: &Node, tree: &DeviceTree) -> TokenStream {
145154
match self {
146-
Action::Instance { raw, device } => {
147-
raw.generate(node, device)
155+
Action::Instance { raw, device, kconfig } => {
156+
raw.generate(node, device, kconfig.as_deref())
148157
}
149158
Action::Labels => {
150159
let nodes = tree.labels.iter().map(|(k, v)| {
@@ -188,19 +197,31 @@ pub enum RawInfo {
188197
}
189198

190199
impl RawInfo {
191-
fn generate(&self, node: &Node, device: &str) -> TokenStream {
200+
fn generate(&self, node: &Node, device: &str, kconfig: Option<&str>) -> TokenStream {
192201
let device_id = str_to_path(device);
202+
let kconfig = if let Some(name) = kconfig {
203+
let name = format_ident!("{}", name);
204+
quote! {
205+
#[cfg(#name)]
206+
}
207+
} else {
208+
quote! {}
209+
};
210+
193211
match self {
194212
RawInfo::Myself => {
195213
let ord = node.ord;
196214
let rawdev = format_ident!("__device_dts_ord_{}", ord);
197215
quote! {
198216
/// Get the raw `const struct device *` of the device tree generated node.
217+
#kconfig
199218
pub unsafe fn get_instance_raw() -> *const crate::raw::device {
200219
&crate::raw::#rawdev
201220
}
202221

222+
#kconfig
203223
static UNIQUE: crate::device::Unique = crate::device::Unique::new();
224+
#kconfig
204225
pub fn get_instance() -> Option<#device_id> {
205226
unsafe {
206227
let device = get_instance_raw();
@@ -226,7 +247,9 @@ impl RawInfo {
226247
let target_route = target.route_to_rust();
227248

228249
quote! {
250+
#kconfig
229251
static UNIQUE: crate::device::Unique = crate::device::Unique::new();
252+
#kconfig
230253
pub fn get_instance() -> Option<#device_id> {
231254
unsafe {
232255
let device = #target_route :: get_instance_raw();
@@ -245,7 +268,9 @@ impl RawInfo {
245268
}
246269

247270
quote! {
271+
#kconfig
248272
static UNIQUE: crate::device::Unique = crate::device::Unique::new();
273+
#kconfig
249274
pub fn get_instance() -> Option<#device_id> {
250275
unsafe {
251276
let device = #path :: get_instance_raw();

zephyr-sys/build.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,19 @@ fn main() -> Result<()> {
7171
.allowlist_function("k_.*")
7272
.allowlist_function("gpio_.*")
7373
.allowlist_function("flash_.*")
74+
.allowlist_function("usb_.*")
7475
.allowlist_item("GPIO_.*")
76+
.allowlist_item("USB_.*")
7577
.allowlist_item("FLASH_.*")
7678
.allowlist_item("Z_.*")
7779
.allowlist_item("ZR_.*")
7880
.allowlist_item("K_.*")
81+
.allowlist_item("uart_line_ctrl")
7982
// Each DT node has a device entry that is a static.
8083
.allowlist_item("__device_dts_ord.*")
8184
.allowlist_function("device_.*")
8285
.allowlist_function("sys_.*")
86+
.allowlist_function("uart_.*")
8387
.allowlist_item("E.*")
8488
.allowlist_item("K_.*")
8589
.allowlist_item("ZR_.*")

zephyr-sys/wrapper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ extern int errno;
4040
#include <zephyr/kernel/thread_stack.h>
4141
#include <zephyr/drivers/gpio.h>
4242
#include <zephyr/drivers/flash.h>
43+
#include <zephyr/drivers/uart.h>
4344

4445
/*
4546
* bindgen will only output #defined constants that resolve to simple numbers. These are some

zephyr/src/device.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::sync::atomic::{AtomicUsize, Ordering};
99

1010
pub mod gpio;
1111
pub mod flash;
12+
pub mod uart;
1213

1314
// Allow dead code, because it isn't required for a given build to have any devices.
1415
/// Device uniqueness.

zephyr/src/device/uart.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//! Simple (and unsafe) wrappers around USB devices.
2+
3+
use crate::raw;
4+
use crate::error::{Error, Result, to_result_void, to_result};
5+
6+
use core::ffi::{c_uchar, c_int};
7+
8+
use super::Unique;
9+
10+
/// A wrapper around a UART device on Zephyr.
11+
pub struct Uart {
12+
/// The underlying device itself.
13+
#[allow(dead_code)]
14+
pub(crate) device: *const raw::device,
15+
}
16+
17+
/// Uart control values.
18+
///
19+
/// This mirrors these definitions from C, but as an enum.
20+
#[repr(u32)]
21+
pub enum LineControl {
22+
/// Baud rate
23+
BaudRate = raw::uart_line_ctrl_UART_LINE_CTRL_BAUD_RATE,
24+
/// Request To Send (RTS)
25+
RTS = raw::uart_line_ctrl_UART_LINE_CTRL_RTS,
26+
/// Data Terminal Ready (DTR)
27+
DTR = raw::uart_line_ctrl_UART_LINE_CTRL_DTR,
28+
/// Data Carrier Detect (DCD)
29+
DCD = raw::uart_line_ctrl_UART_LINE_CTRL_DCD,
30+
/// Data Set Ready (DSR)
31+
DSR = raw::uart_line_ctrl_UART_LINE_CTRL_DSR,
32+
}
33+
34+
impl Uart {
35+
// Note that the `poll_in` and `poll_out` are terrible.
36+
37+
/// Constructor, used by the devicetree generated code.
38+
#[allow(dead_code)]
39+
pub(crate) unsafe fn new(unique: &Unique, device: *const raw::device) -> Option<Uart> {
40+
if !unique.once() {
41+
return None;
42+
}
43+
44+
Some(Uart { device })
45+
}
46+
47+
/// Attempt to read a character from the UART fifo.
48+
///
49+
/// Will return Ok(Some(ch)) if there is a character available, `Ok(None)` if no character
50+
/// is available, or `Err(e)` if there was an error.
51+
pub unsafe fn poll_in(&mut self) -> Result<Option<u8>> {
52+
let mut ch: c_uchar = 0;
53+
54+
match to_result_void(unsafe { raw::uart_poll_in(self.device, &mut ch) }) {
55+
Ok(()) => Ok(Some(ch as u8)),
56+
Err(Error(1)) => Ok(None),
57+
Err(e) => Err(e),
58+
}
59+
}
60+
61+
/// Attempt to write to the outgoing FIFO.
62+
///
63+
/// This writes to the outgoing UART fifo. This will block if the outgoing fifo is full.
64+
pub unsafe fn poll_out(&mut self, out_char: u8) {
65+
unsafe { raw::uart_poll_out(self.device, out_char as c_uchar) }
66+
}
67+
68+
/// Fill FIFO with data.
69+
///
70+
/// This is unspecified what happens if this is not called from IRQ context.
71+
/// Returns Ok(n) for the number of bytes sent.
72+
pub unsafe fn fifo_fill(&mut self, data: &[u8]) -> Result<usize> {
73+
to_result(unsafe {
74+
raw::uart_fifo_fill(self.device, data.as_ptr(), data.len() as c_int)
75+
}).map(|count| count as usize)
76+
}
77+
78+
/// Drain FIFO.
79+
///
80+
/// This is unspecified as to what happens if not called from IRQ context.
81+
pub unsafe fn fifo_read(&mut self, data: &mut [u8]) -> Result<usize> {
82+
to_result(unsafe {
83+
raw::uart_fifo_read(self.device, data.as_mut_ptr(), data.len() as c_int)
84+
}).map(|count| count as usize)
85+
}
86+
87+
/// Read one of the UART line control values.
88+
pub unsafe fn line_ctrl_get(&self, item: LineControl) -> Result<u32> {
89+
let mut result: u32 = 0;
90+
to_result_void(unsafe {
91+
raw::uart_line_ctrl_get(self.device, item as u32, &mut result)
92+
}).map(|()| result)
93+
}
94+
}

0 commit comments

Comments
 (0)