Skip to content

Commit

Permalink
Refactor ioctl! for buffers
Browse files Browse the repository at this point in the history
Instead of relying on the macro user to calculate the length in bytes
do that within the macro itself
  • Loading branch information
Susurrus committed Jul 14, 2017
1 parent 5af1d9d commit 35c2272
Showing 1 changed file with 41 additions and 6 deletions.
47 changes: 41 additions & 6 deletions src/sys/ioctl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,49 @@
//! There is also a `bad none`, `bad write`, and `bad readwrite` form that work similar to the
//! standard `none`, `write`, and `readwrite` forms.
//!
//! Working with arrays
//! --------------------
//!
//! Some `ioctl`s work with entire arrays of elements. These are supported by the `buf` suffix in
//! the `ioctl!` macro which can be used by specifying `read buf`, `write buf`, and
//! `readwrite buf`. Note that there are no "bad" versions for working with buffers. The generated
//! functions include a `len` argument to specify the number of elements (where the type of each
//! element is specified in the macro).
//!
//! Again looking to the SPI `ioctl`s on Linux for an example, `SPI_IOC_NR_TRANSFER` is an `ioctl`
//! that queues up multiple SPI messages, so it writes an entire array of `spi_ioc_transfer`
//! structs. This can be implemented like:
//!
//! ```
//! # #[macro_use] extern crate nix;
//! # use nix::libc::TIOCEXCL as TIOCEXCL;
//! ioctl!(bad none tiocexcl with TIOCEXCL);
//! # const SPI_IOC_MAGIC: nix::libc::c_int = 'k' as nix::libc::c_int;
//! # const SPI_IOC_NR_TRANSFER: u8 = 0;
//! # pub struct spi_ioc_transfer {
//! # field1: u64,
//! # }
//! ioctl!(write buf spi_transfer_buf with SPI_IOC_MAGIC, SPI_IOC_NR_TRANSFER; spi_ioc_transfer);
//! # fn main() {}
//! ```
//!
//! More examples on using `ioctl!` can be found in the [rust-spidev crate](https://github.com/rust-embedded/rust-spidev).
//! This generates a function like:
//!
//! ```
//! # #[macro_use] extern crate nix;
//! # use nix::libc::c_int as c_int;
//! # use nix::libc::c_ulong as c_ulong;
//! # use std::mem;
//! # use nix::{Errno, libc, Result};
//! # const SPI_IOC_MAGIC: u8 = 'k' as u8;
//! # const SPI_IOC_NR_TRANSFER: u8 = 0;
//! # pub struct spi_ioc_transfer {
//! # field1: u64,
//! # }
//! pub unsafe fn spi_transfer_buf(fd: c_int, data: *mut spi_ioc_transfer, len: usize) -> Result<c_int> {
//! let res = libc::ioctl(fd, ior!(SPI_IOC_MAGIC, SPI_IOC_NR_TRANSFER, len * mem::size_of::<u8>()), data);
//! Errno::result(res)
//! }
//! # fn main() {}
//! ```
//!
//! Finding ioctl documentation
//! ---------------------------
Expand Down Expand Up @@ -226,23 +261,23 @@ macro_rules! ioctl {
data: *mut $ty,
len: usize)
-> $crate::Result<$crate::libc::c_int> {
convert_ioctl_res!($crate::libc::ioctl(fd, ior!($ioty, $nr, len) as $crate::sys::ioctl::ioctl_num_type, data))
convert_ioctl_res!($crate::libc::ioctl(fd, ior!($ioty, $nr, len * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
}
);
(write buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
pub unsafe fn $name(fd: $crate::libc::c_int,
data: *const $ty,
len: usize)
-> $crate::Result<$crate::libc::c_int> {
convert_ioctl_res!($crate::libc::ioctl(fd, iow!($ioty, $nr, len) as $crate::sys::ioctl::ioctl_num_type, data))
convert_ioctl_res!($crate::libc::ioctl(fd, iow!($ioty, $nr, len * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
}
);
(readwrite buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
pub unsafe fn $name(fd: $crate::libc::c_int,
data: *mut $ty,
len: usize)
-> $crate::Result<$crate::libc::c_int> {
convert_ioctl_res!($crate::libc::ioctl(fd, iorw!($ioty, $nr, len) as $crate::sys::ioctl::ioctl_num_type, data))
convert_ioctl_res!($crate::libc::ioctl(fd, iorw!($ioty, $nr, len * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
}
);
}

0 comments on commit 35c2272

Please sign in to comment.