| //! Provide helpers for making ioctl system calls. | |
| //! | |
| //! This library is pretty low-level and messy. `ioctl` is not fun. | |
| //! | |
| //! What is an `ioctl`? | |
| //! =================== | |
| //! | |
| //! The `ioctl` syscall is the grab-bag syscall on POSIX systems. Don't want to add a new | |
| //! syscall? Make it an `ioctl`! `ioctl` refers to both the syscall, and the commands that can be | |
| //! sent with it. `ioctl` stands for "IO control", and the commands are always sent to a file | |
| //! descriptor. | |
| //! | |
| //! It is common to see `ioctl`s used for the following purposes: | |
| //! | |
| //! * Provide read/write access to out-of-band data related to a device such as configuration | |
| //! (for instance, setting serial port options) | |
| //! * Provide a mechanism for performing full-duplex data transfers (for instance, xfer on SPI | |
| //! devices). | |
| //! * Provide access to control functions on a device (for example, on Linux you can send | |
| //! commands like pause, resume, and eject to the CDROM device. | |
| //! * Do whatever else the device driver creator thought made most sense. | |
| //! | |
| //! `ioctl`s are synchronous system calls and are similar to read and write calls in that regard. | |
| //! They operate on file descriptors and have an identifier that specifies what the ioctl is. | |
| //! Additionally they may read or write data and therefore need to pass along a data pointer. | |
| //! Besides the semantics of the ioctls being confusing, the generation of this identifer can also | |
| //! be difficult. | |
| //! | |
| //! Historically `ioctl` numbers were arbitrary hard-coded values. In Linux (before 2.6) and some | |
| //! unices this has changed to a more-ordered system where the ioctl numbers are partitioned into | |
| //! subcomponents (For linux this is documented in | |
| //! [`Documentation/ioctl/ioctl-number.rst`](https://elixir.bootlin.com/linux/latest/source/Documentation/userspace-api/ioctl/ioctl-number.rst)): | |
| //! | |
| //! * Number: The actual ioctl ID | |
| //! * Type: A grouping of ioctls for a common purpose or driver | |
| //! * Size: The size in bytes of the data that will be transferred | |
| //! * Direction: Whether there is any data and if it's read, write, or both | |
| //! | |
| //! Newer drivers should not generate complete integer identifiers for their `ioctl`s instead | |
| //! preferring to use the 4 components above to generate the final ioctl identifier. Because of | |
| //! how old `ioctl`s are, however, there are many hard-coded `ioctl` identifiers. These are | |
| //! commonly referred to as "bad" in `ioctl` documentation. | |
| //! | |
| //! Defining `ioctl`s | |
| //! ================= | |
| //! | |
| //! This library provides several `ioctl_*!` macros for binding `ioctl`s. These generate public | |
| //! unsafe functions that can then be used for calling the ioctl. This macro has a few different | |
| //! ways it can be used depending on the specific ioctl you're working with. | |
| //! | |
| //! A simple `ioctl` is `SPI_IOC_RD_MODE`. This ioctl works with the SPI interface on Linux. This | |
| //! specific `ioctl` reads the mode of the SPI device as a `u8`. It's declared in | |
| //! `/include/uapi/linux/spi/spidev.h` as `_IOR(SPI_IOC_MAGIC, 1, __u8)`. Since it uses the `_IOR` | |
| //! macro, we know it's a `read` ioctl and can use the `ioctl_read!` macro as follows: | |
| //! | |
| //! ``` | |
| //! # #[macro_use] extern crate nix; | |
| //! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h | |
| //! const SPI_IOC_TYPE_MODE: u8 = 1; | |
| //! ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8); | |
| //! # fn main() {} | |
| //! ``` | |
| //! | |
| //! This generates the function: | |
| //! | |
| //! ``` | |
| //! # #[macro_use] extern crate nix; | |
| //! # use std::mem; | |
| //! # use nix::{libc, Result}; | |
| //! # use nix::errno::Errno; | |
| //! # use nix::libc::c_int as c_int; | |
| //! # const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h | |
| //! # const SPI_IOC_TYPE_MODE: u8 = 1; | |
| //! pub unsafe fn spi_read_mode(fd: c_int, data: *mut u8) -> Result<c_int> { | |
| //! let res = libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::<u8>()), data); | |
| //! Errno::result(res) | |
| //! } | |
| //! # fn main() {} | |
| //! ``` | |
| //! | |
| //! The return value for the wrapper functions generated by the `ioctl_*!` macros are `nix::Error`s. | |
| //! These are generated by assuming the return value of the ioctl is `-1` on error and everything | |
| //! else is a valid return value. If this is not the case, `Result::map` can be used to map some | |
| //! of the range of "good" values (-Inf..-2, 0..Inf) into a smaller range in a helper function. | |
| //! | |
| //! Writing `ioctl`s generally use pointers as their data source and these should use the | |
| //! `ioctl_write_ptr!`. But in some cases an `int` is passed directly. For these `ioctl`s use the | |
| //! `ioctl_write_int!` macro. This variant does not take a type as the last argument: | |
| //! | |
| //! ``` | |
| //! # #[macro_use] extern crate nix; | |
| //! const HCI_IOC_MAGIC: u8 = b'k'; | |
| //! const HCI_IOC_HCIDEVUP: u8 = 1; | |
| //! ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP); | |
| //! # fn main() {} | |
| //! ``` | |
| //! | |
| //! Some `ioctl`s don't transfer any data, and those should use `ioctl_none!`. This macro | |
| //! doesn't take a type and so it is declared similar to the `write_int` variant shown above. | |
| //! | |
| //! The mode for a given `ioctl` should be clear from the documentation if it has good | |
| //! documentation. Otherwise it will be clear based on the macro used to generate the `ioctl` | |
| //! number where `_IO`, `_IOR`, `_IOW`, and `_IOWR` map to "none", "read", "write_*", and "readwrite" | |
| //! respectively. To determine the specific `write_` variant to use you'll need to find | |
| //! what the argument type is supposed to be. If it's an `int`, then `write_int` should be used, | |
| //! otherwise it should be a pointer and `write_ptr` should be used. On Linux the | |
| //! [`ioctl_list` man page](https://man7.org/linux/man-pages/man2/ioctl_list.2.html) describes a | |
| //! large number of `ioctl`s and describes their argument data type. | |
| //! | |
| //! Using "bad" `ioctl`s | |
| //! -------------------- | |
| //! | |
| //! As mentioned earlier, there are many old `ioctl`s that do not use the newer method of | |
| //! generating `ioctl` numbers and instead use hardcoded values. These can be used with the | |
| //! `ioctl_*_bad!` macros. This naming comes from the Linux kernel which refers to these | |
| //! `ioctl`s as "bad". These are a different variant as they bypass calling the macro that generates | |
| //! the ioctl number and instead use the defined value directly. | |
| //! | |
| //! For example the `TCGETS` `ioctl` reads a `termios` data structure for a given file descriptor. | |
| //! It's defined as `0x5401` in `ioctls.h` on Linux and can be implemented as: | |
| //! | |
| //! ``` | |
| //! # #[macro_use] extern crate nix; | |
| //! # #[cfg(any(target_os = "android", target_os = "linux"))] | |
| //! # use nix::libc::TCGETS as TCGETS; | |
| //! # #[cfg(any(target_os = "android", target_os = "linux"))] | |
| //! # use nix::libc::termios as termios; | |
| //! # #[cfg(any(target_os = "android", target_os = "linux"))] | |
| //! ioctl_read_bad!(tcgets, TCGETS, termios); | |
| //! # fn main() {} | |
| //! ``` | |
| //! | |
| //! The generated function has the same form as that generated by `ioctl_read!`: | |
| //! | |
| //! ```text | |
| //! pub unsafe fn tcgets(fd: c_int, data: *mut termios) -> Result<c_int>; | |
| //! ``` | |
| //! | |
| //! Working with Arrays | |
| //! ------------------- | |
| //! | |
| //! Some `ioctl`s work with entire arrays of elements. These are supported by the `ioctl_*_buf` | |
| //! family of macros: `ioctl_read_buf`, `ioctl_write_buf`, and `ioctl_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, there is a `SPI_IOC_MESSAGE` `ioctl` | |
| //! that queues up multiple SPI messages by writing an entire array of `spi_ioc_transfer` structs. | |
| //! `linux/spi/spidev.h` defines a macro to calculate the `ioctl` number like: | |
| //! | |
| //! ```C | |
| //! #define SPI_IOC_MAGIC 'k' | |
| //! #define SPI_MSGSIZE(N) ... | |
| //! #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) | |
| //! ``` | |
| //! | |
| //! The `SPI_MSGSIZE(N)` calculation is already handled by the `ioctl_*!` macros, so all that's | |
| //! needed to define this `ioctl` is: | |
| //! | |
| //! ``` | |
| //! # #[macro_use] extern crate nix; | |
| //! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h | |
| //! const SPI_IOC_TYPE_MESSAGE: u8 = 0; | |
| //! # pub struct spi_ioc_transfer(u64); | |
| //! ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer); | |
| //! # fn main() {} | |
| //! ``` | |
| //! | |
| //! This generates a function like: | |
| //! | |
| //! ``` | |
| //! # #[macro_use] extern crate nix; | |
| //! # use std::mem; | |
| //! # use nix::{libc, Result}; | |
| //! # use nix::errno::Errno; | |
| //! # use nix::libc::c_int as c_int; | |
| //! # const SPI_IOC_MAGIC: u8 = b'k'; | |
| //! # const SPI_IOC_TYPE_MESSAGE: u8 = 0; | |
| //! # pub struct spi_ioc_transfer(u64); | |
| //! pub unsafe fn spi_message(fd: c_int, data: &mut [spi_ioc_transfer]) -> Result<c_int> { | |
| //! let res = libc::ioctl(fd, | |
| //! request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()), | |
| //! data); | |
| //! Errno::result(res) | |
| //! } | |
| //! # fn main() {} | |
| //! ``` | |
| //! | |
| //! Finding `ioctl` Documentation | |
| //! ----------------------------- | |
| //! | |
| //! For Linux, look at your system's headers. For example, `/usr/include/linux/input.h` has a lot | |
| //! of lines defining macros which use `_IO`, `_IOR`, `_IOW`, `_IOC`, and `_IOWR`. Some `ioctl`s are | |
| //! documented directly in the headers defining their constants, but others have more extensive | |
| //! documentation in man pages (like termios' `ioctl`s which are in `tty_ioctl(4)`). | |
| //! | |
| //! Documenting the Generated Functions | |
| //! =================================== | |
| //! | |
| //! In many cases, users will wish for the functions generated by the `ioctl` | |
| //! macro to be public and documented. For this reason, the generated functions | |
| //! are public by default. If you wish to hide the ioctl, you will need to put | |
| //! them in a private module. | |
| //! | |
| //! For documentation, it is possible to use doc comments inside the `ioctl_*!` macros. Here is an | |
| //! example : | |
| //! | |
| //! ``` | |
| //! # #[macro_use] extern crate nix; | |
| //! # use nix::libc::c_int; | |
| //! ioctl_read! { | |
| //! /// Make the given terminal the controlling terminal of the calling process. The calling | |
| //! /// process must be a session leader and not have a controlling terminal already. If the | |
| //! /// terminal is already the controlling terminal of a different session group then the | |
| //! /// ioctl will fail with **EPERM**, unless the caller is root (more precisely: has the | |
| //! /// **CAP_SYS_ADMIN** capability) and arg equals 1, in which case the terminal is stolen | |
| //! /// and all processes that had it as controlling terminal lose it. | |
| //! tiocsctty, b't', 19, c_int | |
| //! } | |
| //! | |
| //! # fn main() {} | |
| //! ``` | |
| use cfg_if::cfg_if; | |
| #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] | |
| #[macro_use] | |
| mod linux; | |
| #[cfg(any( | |
| target_os = "android", | |
| target_os = "linux", | |
| target_os = "redox" | |
| ))] | |
| pub use self::linux::*; | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "illumos", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "haiku", | |
| target_os = "openbsd" | |
| ))] | |
| #[macro_use] | |
| mod bsd; | |
| #[cfg(any( | |
| target_os = "dragonfly", | |
| target_os = "freebsd", | |
| target_os = "illumos", | |
| target_os = "ios", | |
| target_os = "macos", | |
| target_os = "netbsd", | |
| target_os = "haiku", | |
| target_os = "openbsd" | |
| ))] | |
| pub use self::bsd::*; | |
| /// Convert raw ioctl return value to a Nix result | |
| #[macro_export] | |
| #[doc(hidden)] | |
| macro_rules! convert_ioctl_res { | |
| ($w:expr) => {{ | |
| $crate::errno::Errno::result($w) | |
| }}; | |
| } | |
| /// Generates a wrapper function for an ioctl that passes no data to the kernel. | |
| /// | |
| /// The arguments to this macro are: | |
| /// | |
| /// * The function name | |
| /// * The ioctl identifier | |
| /// * The ioctl sequence number | |
| /// | |
| /// The generated function has the following signature: | |
| /// | |
| /// ```rust,ignore | |
| /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int> | |
| /// ``` | |
| /// | |
| /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). | |
| /// | |
| /// # Example | |
| /// | |
| /// The `videodev2` driver on Linux defines the `log_status` `ioctl` as: | |
| /// | |
| /// ```C | |
| /// #define VIDIOC_LOG_STATUS _IO('V', 70) | |
| /// ``` | |
| /// | |
| /// This can be implemented in Rust like: | |
| /// | |
| /// ```no_run | |
| /// # #[macro_use] extern crate nix; | |
| /// ioctl_none!(log_status, b'V', 70); | |
| /// fn main() {} | |
| /// ``` | |
| #[macro_export(local_inner_macros)] | |
| macro_rules! ioctl_none { | |
| ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => ( | |
| $(#[$attr])* | |
| pub unsafe fn $name(fd: $crate::libc::c_int) | |
| -> $crate::Result<$crate::libc::c_int> { | |
| convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type)) | |
| } | |
| ) | |
| } | |
| /// Generates a wrapper function for a "bad" ioctl that passes no data to the kernel. | |
| /// | |
| /// The arguments to this macro are: | |
| /// | |
| /// * The function name | |
| /// * The ioctl request code | |
| /// | |
| /// The generated function has the following signature: | |
| /// | |
| /// ```rust,ignore | |
| /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int> | |
| /// ``` | |
| /// | |
| /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). | |
| /// | |
| /// # Example | |
| /// | |
| /// ```no_run | |
| /// # #[macro_use] extern crate nix; | |
| /// # use libc::TIOCNXCL; | |
| /// # use std::fs::File; | |
| /// # use std::os::unix::io::AsRawFd; | |
| /// ioctl_none_bad!(tiocnxcl, TIOCNXCL); | |
| /// fn main() { | |
| /// let file = File::open("/dev/ttyUSB0").unwrap(); | |
| /// unsafe { tiocnxcl(file.as_raw_fd()) }.unwrap(); | |
| /// } | |
| /// ``` | |
| // TODO: add an example using request_code_*!() | |
| #[macro_export(local_inner_macros)] | |
| macro_rules! ioctl_none_bad { | |
| ($(#[$attr:meta])* $name:ident, $nr:expr) => ( | |
| $(#[$attr])* | |
| pub unsafe fn $name(fd: $crate::libc::c_int) | |
| -> $crate::Result<$crate::libc::c_int> { | |
| convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type)) | |
| } | |
| ) | |
| } | |
| /// Generates a wrapper function for an ioctl that reads data from the kernel. | |
| /// | |
| /// The arguments to this macro are: | |
| /// | |
| /// * The function name | |
| /// * The ioctl identifier | |
| /// * The ioctl sequence number | |
| /// * The data type passed by this ioctl | |
| /// | |
| /// The generated function has the following signature: | |
| /// | |
| /// ```rust,ignore | |
| /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int> | |
| /// ``` | |
| /// | |
| /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). | |
| /// | |
| /// # Example | |
| /// | |
| /// ``` | |
| /// # #[macro_use] extern crate nix; | |
| /// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h | |
| /// const SPI_IOC_TYPE_MODE: u8 = 1; | |
| /// ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8); | |
| /// # fn main() {} | |
| /// ``` | |
| #[macro_export(local_inner_macros)] | |
| macro_rules! ioctl_read { | |
| ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( | |
| $(#[$attr])* | |
| pub unsafe fn $name(fd: $crate::libc::c_int, | |
| data: *mut $ty) | |
| -> $crate::Result<$crate::libc::c_int> { | |
| convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) | |
| } | |
| ) | |
| } | |
| /// Generates a wrapper function for a "bad" ioctl that reads data from the kernel. | |
| /// | |
| /// The arguments to this macro are: | |
| /// | |
| /// * The function name | |
| /// * The ioctl request code | |
| /// * The data type passed by this ioctl | |
| /// | |
| /// The generated function has the following signature: | |
| /// | |
| /// ```rust,ignore | |
| /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int> | |
| /// ``` | |
| /// | |
| /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). | |
| /// | |
| /// # Example | |
| /// | |
| /// ``` | |
| /// # #[macro_use] extern crate nix; | |
| /// # #[cfg(any(target_os = "android", target_os = "linux"))] | |
| /// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios); | |
| /// # fn main() {} | |
| /// ``` | |
| #[macro_export(local_inner_macros)] | |
| macro_rules! ioctl_read_bad { | |
| ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => ( | |
| $(#[$attr])* | |
| pub unsafe fn $name(fd: $crate::libc::c_int, | |
| data: *mut $ty) | |
| -> $crate::Result<$crate::libc::c_int> { | |
| convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) | |
| } | |
| ) | |
| } | |
| /// Generates a wrapper function for an ioctl that writes data through a pointer to the kernel. | |
| /// | |
| /// The arguments to this macro are: | |
| /// | |
| /// * The function name | |
| /// * The ioctl identifier | |
| /// * The ioctl sequence number | |
| /// * The data type passed by this ioctl | |
| /// | |
| /// The generated function has the following signature: | |
| /// | |
| /// ```rust,ignore | |
| /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int> | |
| /// ``` | |
| /// | |
| /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). | |
| /// | |
| /// # Example | |
| /// | |
| /// ``` | |
| /// # #[macro_use] extern crate nix; | |
| /// # pub struct v4l2_audio {} | |
| /// ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio); | |
| /// # fn main() {} | |
| /// ``` | |
| #[macro_export(local_inner_macros)] | |
| macro_rules! ioctl_write_ptr { | |
| ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( | |
| $(#[$attr])* | |
| pub unsafe fn $name(fd: $crate::libc::c_int, | |
| data: *const $ty) | |
| -> $crate::Result<$crate::libc::c_int> { | |
| convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) | |
| } | |
| ) | |
| } | |
| /// Generates a wrapper function for a "bad" ioctl that writes data through a pointer to the kernel. | |
| /// | |
| /// The arguments to this macro are: | |
| /// | |
| /// * The function name | |
| /// * The ioctl request code | |
| /// * The data type passed by this ioctl | |
| /// | |
| /// The generated function has the following signature: | |
| /// | |
| /// ```rust,ignore | |
| /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int> | |
| /// ``` | |
| /// | |
| /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). | |
| /// | |
| /// # Example | |
| /// | |
| /// ``` | |
| /// # #[macro_use] extern crate nix; | |
| /// # #[cfg(any(target_os = "android", target_os = "linux"))] | |
| /// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios); | |
| /// # fn main() {} | |
| /// ``` | |
| #[macro_export(local_inner_macros)] | |
| macro_rules! ioctl_write_ptr_bad { | |
| ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => ( | |
| $(#[$attr])* | |
| pub unsafe fn $name(fd: $crate::libc::c_int, | |
| data: *const $ty) | |
| -> $crate::Result<$crate::libc::c_int> { | |
| convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) | |
| } | |
| ) | |
| } | |
| cfg_if! { | |
| if #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] { | |
| /// Generates a wrapper function for a ioctl that writes an integer to the kernel. | |
| /// | |
| /// The arguments to this macro are: | |
| /// | |
| /// * The function name | |
| /// * The ioctl identifier | |
| /// * The ioctl sequence number | |
| /// | |
| /// The generated function has the following signature: | |
| /// | |
| /// ```rust,ignore | |
| /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int> | |
| /// ``` | |
| /// | |
| /// `nix::sys::ioctl::ioctl_param_type` depends on the OS: | |
| /// * BSD - `libc::c_int` | |
| /// * Linux - `libc::c_ulong` | |
| /// | |
| /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). | |
| /// | |
| /// # Example | |
| /// | |
| /// ``` | |
| /// # #[macro_use] extern crate nix; | |
| /// ioctl_write_int!(vt_activate, b'v', 4); | |
| /// # fn main() {} | |
| /// ``` | |
| #[macro_export(local_inner_macros)] | |
| macro_rules! ioctl_write_int { | |
| ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => ( | |
| $(#[$attr])* | |
| pub unsafe fn $name(fd: $crate::libc::c_int, | |
| data: $crate::sys::ioctl::ioctl_param_type) | |
| -> $crate::Result<$crate::libc::c_int> { | |
| convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data)) | |
| } | |
| ) | |
| } | |
| } else { | |
| /// Generates a wrapper function for a ioctl that writes an integer to the kernel. | |
| /// | |
| /// The arguments to this macro are: | |
| /// | |
| /// * The function name | |
| /// * The ioctl identifier | |
| /// * The ioctl sequence number | |
| /// | |
| /// The generated function has the following signature: | |
| /// | |
| /// ```rust,ignore | |
| /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int> | |
| /// ``` | |
| /// | |
| /// `nix::sys::ioctl::ioctl_param_type` depends on the OS: | |
| /// * BSD - `libc::c_int` | |
| /// * Linux - `libc::c_ulong` | |
| /// | |
| /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). | |
| /// | |
| /// # Example | |
| /// | |
| /// ``` | |
| /// # #[macro_use] extern crate nix; | |
| /// const HCI_IOC_MAGIC: u8 = b'k'; | |
| /// const HCI_IOC_HCIDEVUP: u8 = 1; | |
| /// ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP); | |
| /// # fn main() {} | |
| /// ``` | |
| #[macro_export(local_inner_macros)] | |
| macro_rules! ioctl_write_int { | |
| ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => ( | |
| $(#[$attr])* | |
| pub unsafe fn $name(fd: $crate::libc::c_int, | |
| data: $crate::sys::ioctl::ioctl_param_type) | |
| -> $crate::Result<$crate::libc::c_int> { | |
| convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data)) | |
| } | |
| ) | |
| } | |
| } | |
| } | |
| /// Generates a wrapper function for a "bad" ioctl that writes an integer to the kernel. | |
| /// | |
| /// The arguments to this macro are: | |
| /// | |
| /// * The function name | |
| /// * The ioctl request code | |
| /// | |
| /// The generated function has the following signature: | |
| /// | |
| /// ```rust,ignore | |
| /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: libc::c_int) -> Result<libc::c_int> | |
| /// ``` | |
| /// | |
| /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). | |
| /// | |
| /// # Examples | |
| /// | |
| /// ``` | |
| /// # #[macro_use] extern crate nix; | |
| /// # #[cfg(any(target_os = "android", target_os = "linux"))] | |
| /// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK); | |
| /// # fn main() {} | |
| /// ``` | |
| /// | |
| /// ```rust | |
| /// # #[macro_use] extern crate nix; | |
| /// const KVMIO: u8 = 0xAE; | |
| /// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03)); | |
| /// # fn main() {} | |
| /// ``` | |
| #[macro_export(local_inner_macros)] | |
| macro_rules! ioctl_write_int_bad { | |
| ($(#[$attr:meta])* $name:ident, $nr:expr) => ( | |
| $(#[$attr])* | |
| pub unsafe fn $name(fd: $crate::libc::c_int, | |
| data: $crate::libc::c_int) | |
| -> $crate::Result<$crate::libc::c_int> { | |
| convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) | |
| } | |
| ) | |
| } | |
| /// Generates a wrapper function for an ioctl that reads and writes data to the kernel. | |
| /// | |
| /// The arguments to this macro are: | |
| /// | |
| /// * The function name | |
| /// * The ioctl identifier | |
| /// * The ioctl sequence number | |
| /// * The data type passed by this ioctl | |
| /// | |
| /// The generated function has the following signature: | |
| /// | |
| /// ```rust,ignore | |
| /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int> | |
| /// ``` | |
| /// | |
| /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). | |
| /// | |
| /// # Example | |
| /// | |
| /// ``` | |
| /// # #[macro_use] extern crate nix; | |
| /// # pub struct v4l2_audio {} | |
| /// ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio); | |
| /// # fn main() {} | |
| /// ``` | |
| #[macro_export(local_inner_macros)] | |
| macro_rules! ioctl_readwrite { | |
| ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( | |
| $(#[$attr])* | |
| pub unsafe fn $name(fd: $crate::libc::c_int, | |
| data: *mut $ty) | |
| -> $crate::Result<$crate::libc::c_int> { | |
| convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data)) | |
| } | |
| ) | |
| } | |
| /// Generates a wrapper function for a "bad" ioctl that reads and writes data to the kernel. | |
| /// | |
| /// The arguments to this macro are: | |
| /// | |
| /// * The function name | |
| /// * The ioctl request code | |
| /// * The data type passed by this ioctl | |
| /// | |
| /// The generated function has the following signature: | |
| /// | |
| /// ```rust,ignore | |
| /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int> | |
| /// ``` | |
| /// | |
| /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). | |
| // TODO: Find an example for ioctl_readwrite_bad | |
| #[macro_export(local_inner_macros)] | |
| macro_rules! ioctl_readwrite_bad { | |
| ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => ( | |
| $(#[$attr])* | |
| pub unsafe fn $name(fd: $crate::libc::c_int, | |
| data: *mut $ty) | |
| -> $crate::Result<$crate::libc::c_int> { | |
| convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data)) | |
| } | |
| ) | |
| } | |
| /// Generates a wrapper function for an ioctl that reads an array of elements from the kernel. | |
| /// | |
| /// The arguments to this macro are: | |
| /// | |
| /// * The function name | |
| /// * The ioctl identifier | |
| /// * The ioctl sequence number | |
| /// * The data type passed by this ioctl | |
| /// | |
| /// The generated function has the following signature: | |
| /// | |
| /// ```rust,ignore | |
| /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int> | |
| /// ``` | |
| /// | |
| /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). | |
| // TODO: Find an example for ioctl_read_buf | |
| #[macro_export(local_inner_macros)] | |
| macro_rules! ioctl_read_buf { | |
| ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( | |
| $(#[$attr])* | |
| pub unsafe fn $name(fd: $crate::libc::c_int, | |
| data: &mut [$ty]) | |
| -> $crate::Result<$crate::libc::c_int> { | |
| convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data)) | |
| } | |
| ) | |
| } | |
| /// Generates a wrapper function for an ioctl that writes an array of elements to the kernel. | |
| /// | |
| /// The arguments to this macro are: | |
| /// | |
| /// * The function name | |
| /// * The ioctl identifier | |
| /// * The ioctl sequence number | |
| /// * The data type passed by this ioctl | |
| /// | |
| /// The generated function has the following signature: | |
| /// | |
| /// ```rust,ignore | |
| /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &[DATA_TYPE]) -> Result<libc::c_int> | |
| /// ``` | |
| /// | |
| /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). | |
| /// | |
| /// # Examples | |
| /// | |
| /// ``` | |
| /// # #[macro_use] extern crate nix; | |
| /// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h | |
| /// const SPI_IOC_TYPE_MESSAGE: u8 = 0; | |
| /// # pub struct spi_ioc_transfer(u64); | |
| /// ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer); | |
| /// # fn main() {} | |
| /// ``` | |
| #[macro_export(local_inner_macros)] | |
| macro_rules! ioctl_write_buf { | |
| ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( | |
| $(#[$attr])* | |
| pub unsafe fn $name(fd: $crate::libc::c_int, | |
| data: &[$ty]) | |
| -> $crate::Result<$crate::libc::c_int> { | |
| convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data)) | |
| } | |
| ) | |
| } | |
| /// Generates a wrapper function for an ioctl that reads and writes an array of elements to the kernel. | |
| /// | |
| /// The arguments to this macro are: | |
| /// | |
| /// * The function name | |
| /// * The ioctl identifier | |
| /// * The ioctl sequence number | |
| /// * The data type passed by this ioctl | |
| /// | |
| /// The generated function has the following signature: | |
| /// | |
| /// ```rust,ignore | |
| /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int> | |
| /// ``` | |
| /// | |
| /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html). | |
| // TODO: Find an example for readwrite_buf | |
| #[macro_export(local_inner_macros)] | |
| macro_rules! ioctl_readwrite_buf { | |
| ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => ( | |
| $(#[$attr])* | |
| pub unsafe fn $name(fd: $crate::libc::c_int, | |
| data: &mut [$ty]) | |
| -> $crate::Result<$crate::libc::c_int> { | |
| convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of_val(data)) as $crate::sys::ioctl::ioctl_num_type, data)) | |
| } | |
| ) | |
| } |