Skip to content

Commit 3b87bc8

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 c8cbbab commit 3b87bc8

File tree

2 files changed

+61
-20
lines changed

2 files changed

+61
-20
lines changed

src/sys/ioctl/mod.rs

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,55 @@
140140
//! There is also a `bad none`, `bad write_int`/`bad write_ptr`, and `bad readwrite` variant that work
141141
//! similar to the standard `none`, `write_int`/`write_ptr`, and `readwrite` variants.
142142
//!
143+
//! Working with arrays
144+
//! --------------------
145+
//!
146+
//! Some `ioctl`s work with entire arrays of elements. These are supported by the `*_buf` variants in
147+
//! the `ioctl!` macro which can be used by specifying `read_buf`, `write_buf`, and
148+
//! `readwrite_buf`. Note that there are no "bad" versions for working with buffers. The generated
149+
//! functions include a `len` argument to specify the number of elements (where the type of each
150+
//! element is specified in the macro).
151+
//!
152+
//! Again looking to the SPI `ioctl`s on Linux for an example, there is a `SPI_IOC_MESSAGE` `ioctl`
153+
//! that queues up multiple SPI messages by writing an entire array of `spi_ioc_transfer` structs.
154+
//! `linux/spi/spidev.h` defines a macro to calculate the `ioctl` number like:
155+
//!
156+
//! ```C
157+
//! #define SPI_IOC_MAGIC 'k'
158+
//! #define SPI_MSGSIZE(N) ...
159+
//! #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
160+
//! ```
161+
//!
162+
//! The `SPI_MSGSIZE(N)` calculation is already handled by the `ioctl!` macro, so all that's
163+
//! needed to define this `ioctl` is:
164+
//!
143165
//! ```
144166
//! # #[macro_use] extern crate nix;
145-
//! # use nix::libc::TIOCEXCL as TIOCEXCL;
146-
//! ioctl!(bad none tiocexcl with TIOCEXCL);
167+
//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
168+
//! const SPI_IOC_TYPE_MESSAGE: u8 = 0;
169+
//! # pub struct spi_ioc_transfer(u64);
170+
//! ioctl!(write_buf spi_transfer with SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE; spi_ioc_transfer);
147171
//! # fn main() {}
148172
//! ```
149173
//!
150-
//! More examples on using `ioctl!` can be found in the [rust-spidev crate](https://github.com/rust-embedded/rust-spidev).
174+
//! This generates a function like:
175+
//!
176+
//! ```
177+
//! # #[macro_use] extern crate nix;
178+
//! # use std::mem;
179+
//! # use nix::{Errno, libc, Result};
180+
//! # use nix::libc::c_int as c_int;
181+
//! # const SPI_IOC_MAGIC: u8 = b'k';
182+
//! # const SPI_IOC_TYPE_MESSAGE: u8 = 0;
183+
//! # pub struct spi_ioc_transfer(u64);
184+
//! pub unsafe fn spi_message(fd: c_int, data: &mut [spi_ioc_transfer]) -> Result<c_int> {
185+
//! let res = libc::ioctl(fd,
186+
//! iow!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()),
187+
//! data);
188+
//! Errno::result(res)
189+
//! }
190+
//! # fn main() {}
191+
//! ```
151192
//!
152193
//! Finding ioctl documentation
153194
//! ---------------------------
@@ -255,28 +296,25 @@ macro_rules! ioctl {
255296
convert_ioctl_res!($crate::libc::ioctl(fd, iorw!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
256297
}
257298
);
258-
(read buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
299+
(read_buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
259300
pub unsafe fn $name(fd: $crate::libc::c_int,
260-
data: *mut $ty,
261-
len: usize)
301+
data: &mut [$ty])
262302
-> $crate::Result<$crate::libc::c_int> {
263-
convert_ioctl_res!($crate::libc::ioctl(fd, ior!($ioty, $nr, len) as $crate::sys::ioctl::ioctl_num_type, data))
303+
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))
264304
}
265305
);
266-
(write buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
306+
(write_buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
267307
pub unsafe fn $name(fd: $crate::libc::c_int,
268-
data: *const $ty,
269-
len: usize)
308+
data: &[$ty])
270309
-> $crate::Result<$crate::libc::c_int> {
271-
convert_ioctl_res!($crate::libc::ioctl(fd, iow!($ioty, $nr, len) as $crate::sys::ioctl::ioctl_num_type, data))
310+
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))
272311
}
273312
);
274-
(readwrite buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
313+
(readwrite_buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
275314
pub unsafe fn $name(fd: $crate::libc::c_int,
276-
data: *mut $ty,
277-
len: usize)
315+
data: &mut [$ty])
278316
-> $crate::Result<$crate::libc::c_int> {
279-
convert_ioctl_res!($crate::libc::ioctl(fd, iorw!($ioty, $nr, len) as $crate::sys::ioctl::ioctl_num_type, data))
317+
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))
280318
}
281319
);
282320
}

test/sys/test_ioctl.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ ioctl!(write_ptr write_ptr_u8 with 0, 0; u8);
1313
ioctl!(write_ptr write_ptr_u32 with 0, 0; u32);
1414
ioctl!(write_ptr write_ptr_u64 with 0, 0; u64);
1515
ioctl!(readwrite readwrite_test with 0, 0; u64);
16-
ioctl!(read buf readbuf_test with 0, 0; u32);
17-
ioctl!(write buf writebuf_test_u8 with 0, 0; u8);
18-
ioctl!(write buf writebuf_test_u32 with 0, 0; u32);
19-
ioctl!(write buf writebuf_test_u64 with 0, 0; u64);
20-
ioctl!(readwrite buf readwritebuf_test with 0, 0; u32);
16+
ioctl!(read_buf readbuf_test with 0, 0; u32);
17+
const SPI_IOC_MAGIC: u8 = b'k';
18+
const SPI_IOC_MESSAGE: u8 = 0;
19+
ioctl!(write_buf writebuf_test_consts with SPI_IOC_MAGIC, SPI_IOC_MESSAGE; u8);
20+
ioctl!(write_buf writebuf_test_u8 with 0, 0; u8);
21+
ioctl!(write_buf writebuf_test_u32 with 0, 0; u32);
22+
ioctl!(write_buf writebuf_test_u64 with 0, 0; u64);
23+
ioctl!(readwrite_buf readwritebuf_test with 0, 0; u32);
2124

2225
// See C code for source of values for op calculations (does NOT work for mips/powerpc):
2326
// https://gist.github.com/posborne/83ea6880770a1aef332e

0 commit comments

Comments
 (0)