Skip to content

Commit b532033

Browse files
committed
Refactor ioctl! for buffers
Instead of relying on the macro user to calculate the length in bytes do that within the macro itself
1 parent b44bc15 commit b532033

File tree

2 files changed

+51
-12
lines changed

2 files changed

+51
-12
lines changed

src/sys/ioctl/mod.rs

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,53 @@
125125
//! There is also a `bad none`, `bad write`, and `bad readwrite` form that work similar to the
126126
//! standard `none`, `write`, and `readwrite` forms.
127127
//!
128+
//! Working with arrays
129+
//! --------------------
130+
//!
131+
//! Some `ioctl`s work with entire arrays of elements. These are supported by the `buf` suffix in
132+
//! the `ioctl!` macro which can be used by specifying `read buf`, `write buf`, and
133+
//! `readwrite buf`. Note that there are no "bad" versions for working with buffers. The generated
134+
//! functions include a `len` argument to specify the number of elements (where the type of each
135+
//! element is specified in the macro).
136+
//!
137+
//! Again looking to the SPI `ioctl`s on Linux for an example, there is a `SPI_IOC_MESSAGE` `ioctl`
138+
//! that queues up multiple SPI messages by writing an entire array of `spi_ioc_transfer` structs.
139+
//! `linux/spi/spidev.h` defines a macro to calculate the `ioctl` number like:
140+
//!
141+
//! ```C
142+
//! #define SPI_IOC_MAGIC 'k'
143+
//! #define SPI_MSGSIZE(N) ...
144+
//! #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
145+
//! ```
146+
//!
147+
//! The `SPI_MSGSIZE(N)` calculation is already handled by the `ioctl!` macro, so all that's
148+
//! needed to define this `ioctl` is:
149+
//!
128150
//! ```
129151
//! # #[macro_use] extern crate nix;
130-
//! # use nix::libc::TIOCEXCL as TIOCEXCL;
131-
//! ioctl!(bad none tiocexcl with TIOCEXCL);
152+
//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
153+
//! const SPI_IOC_TYPE_MESSAGE: u8 = 0;
154+
//! # pub struct spi_ioc_transfer(u64);
155+
//! ioctl!(write buf spi_transfer with SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE; spi_ioc_transfer);
132156
//! # fn main() {}
133157
//! ```
134158
//!
135-
//! More examples on using `ioctl!` can be found in the [rust-spidev crate](https://github.com/rust-embedded/rust-spidev).
159+
//! This generates a function like:
160+
//!
161+
//! ```
162+
//! # #[macro_use] extern crate nix;
163+
//! # use std::mem;
164+
//! # use nix::{Errno, libc, Result};
165+
//! # use nix::libc::c_int as c_int;
166+
//! # const SPI_IOC_MAGIC: u8 = b'k';
167+
//! # const SPI_IOC_TYPE_MESSAGE: u8 = 0;
168+
//! # pub struct spi_ioc_transfer(u64);
169+
//! pub unsafe fn spi_message(fd: c_int, data: &mut [spi_ioc_transfer]) -> Result<c_int> {
170+
//! let res = libc::ioctl(fd, iow!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()), data);
171+
//! Errno::result(res)
172+
//! }
173+
//! # fn main() {}
174+
//! ```
136175
//!
137176
//! Finding ioctl documentation
138177
//! ---------------------------
@@ -228,26 +267,23 @@ macro_rules! ioctl {
228267
);
229268
(read buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
230269
pub unsafe fn $name(fd: $crate::libc::c_int,
231-
data: *mut $ty,
232-
len: usize)
270+
data: &mut [$ty])
233271
-> $crate::Result<$crate::libc::c_int> {
234-
convert_ioctl_res!($crate::libc::ioctl(fd, ior!($ioty, $nr, len) as $crate::sys::ioctl::ioctl_num_type, data))
272+
convert_ioctl_res!($crate::libc::ioctl(fd, ior!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
235273
}
236274
);
237275
(write buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
238276
pub unsafe fn $name(fd: $crate::libc::c_int,
239-
data: *const $ty,
240-
len: usize)
277+
data: &[$ty])
241278
-> $crate::Result<$crate::libc::c_int> {
242-
convert_ioctl_res!($crate::libc::ioctl(fd, iow!($ioty, $nr, len) as $crate::sys::ioctl::ioctl_num_type, data))
279+
convert_ioctl_res!($crate::libc::ioctl(fd, iow!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
243280
}
244281
);
245282
(readwrite buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
246283
pub unsafe fn $name(fd: $crate::libc::c_int,
247-
data: *mut $ty,
248-
len: usize)
284+
data: &mut [$ty])
249285
-> $crate::Result<$crate::libc::c_int> {
250-
convert_ioctl_res!($crate::libc::ioctl(fd, iorw!($ioty, $nr, len) as $crate::sys::ioctl::ioctl_num_type, data))
286+
convert_ioctl_res!($crate::libc::ioctl(fd, iorw!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
251287
}
252288
);
253289
}

test/sys/test_ioctl.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ ioctl!(write write_test_u32 with 0, 0; u32);
1212
ioctl!(write write_test_u64 with 0, 0; u64);
1313
ioctl!(readwrite readwrite_test with 0, 0; u64);
1414
ioctl!(read buf readbuf_test with 0, 0; u32);
15+
const SPI_IOC_MAGIC: u8 = b'k';
16+
const SPI_IOC_MESSAGE: u8 = 0;
17+
ioctl!(write buf writebuf_test_consts with SPI_IOC_MAGIC, SPI_IOC_MESSAGE; u8);
1518
ioctl!(write buf writebuf_test_u8 with 0, 0; u8);
1619
ioctl!(write buf writebuf_test_u32 with 0, 0; u32);
1720
ioctl!(write buf writebuf_test_u64 with 0, 0; u64);

0 commit comments

Comments
 (0)