1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
//! Provide helpers for making ioctl system calls //! //! Currently supports Linux on all architectures. Other platforms welcome! //! //! 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 send 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. //! //! What does this module support? //! =============================== //! //! This library provides the `ioctl!` macro, for binding `ioctl`s. //! Here's a few examples of how that can work for SPI under Linux //! from [rust-spidev](https://github.com/posborne/rust-spidev). //! //! ``` //! #[macro_use] extern crate nix; //! //! #[allow(non_camel_case_types)] //! pub struct spi_ioc_transfer { //! pub tx_buf: u64, //! pub rx_buf: u64, //! pub len: u32, //! //! // optional overrides //! pub speed_hz: u32, //! pub delay_usecs: u16, //! pub bits_per_word: u8, //! pub cs_change: u8, //! pub pad: u32, //! } //! //! #[cfg(linux)] //! mod ioctl { //! use super::*; //! //! const SPI_IOC_MAGIC: u8 = 'k' as u8; //! const SPI_IOC_NR_TRANSFER: u8 = 0; //! const SPI_IOC_NR_MODE: u8 = 1; //! const SPI_IOC_NR_LSB_FIRST: u8 = 2; //! const SPI_IOC_NR_BITS_PER_WORD: u8 = 3; //! const SPI_IOC_NR_MAX_SPEED_HZ: u8 = 4; //! const SPI_IOC_NR_MODE32: u8 = 5; //! //! ioctl!(read get_mode_u8 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u8); //! ioctl!(read get_mode_u32 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u32); //! ioctl!(write set_mode_u8 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u8); //! ioctl!(write set_mode_u32 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE32; u32); //! ioctl!(read get_lsb_first with SPI_IOC_MAGIC, SPI_IOC_NR_LSB_FIRST; u8); //! ioctl!(write set_lsb_first with SPI_IOC_MAGIC, SPI_IOC_NR_LSB_FIRST; u8); //! ioctl!(read get_bits_per_word with SPI_IOC_MAGIC, SPI_IOC_NR_BITS_PER_WORD; u8); //! ioctl!(write set_bits_per_word with SPI_IOC_MAGIC, SPI_IOC_NR_BITS_PER_WORD; u8); //! ioctl!(read get_max_speed_hz with SPI_IOC_MAGIC, SPI_IOC_NR_MAX_SPEED_HZ; u32); //! ioctl!(write set_max_speed_hz with SPI_IOC_MAGIC, SPI_IOC_NR_MAX_SPEED_HZ; u32); //! ioctl!(write spidev_transfer with SPI_IOC_MAGIC, SPI_IOC_NR_TRANSFER; spi_ioc_transfer); //! ioctl!(write buf spidev_transfer_buf with SPI_IOC_MAGIC, SPI_IOC_NR_TRANSFER; spi_ioc_transfer); //! } //! //! // doctest workaround //! fn main() {} //! ``` //! //! Spidev uses the `_IOC` macros that are encouraged (as far as //! `ioctl` can be encouraged at all) for newer drivers. Many //! drivers, however, just use magic numbers with no attached //! semantics. For those, the `ioctl!(bad ...)` variant should be //! used (the "bad" terminology is from the Linux kernel). //! //! How do I get the magic numbers? //! =============================== //! //! For Linux, look at your system's headers. For example, `/usr/include/linxu/input.h` has a lot //! of lines defining macros which use `_IOR`, `_IOW`, `_IOC`, and `_IORW`. These macros //! correspond to the `ior!`, `iow!`, `ioc!`, and `iorw!` macros defined in this crate. //! Additionally, there is the `ioctl!` macro for creating a wrapper around `ioctl` that is //! somewhat more type-safe. //! //! Most `ioctl`s have no or little documentation. You'll need to scrounge through //! the source to figure out what they do and how they should be used. //! #[cfg(any(target_os = "linux", target_os = "android"))] #[path = "platform/linux.rs"] #[macro_use] mod platform; #[cfg(target_os = "macos")] #[path = "platform/macos.rs"] #[macro_use] mod platform; #[cfg(target_os = "ios")] #[path = "platform/ios.rs"] #[macro_use] mod platform; #[cfg(target_os = "freebsd")] #[path = "platform/freebsd.rs"] #[macro_use] mod platform; #[cfg(target_os = "netbsd")] #[path = "platform/netbsd.rs"] #[macro_use] mod platform; #[cfg(target_os = "openbsd")] #[path = "platform/openbsd.rs"] #[macro_use] mod platform; #[cfg(target_os = "dragonfly")] #[path = "platform/dragonfly.rs"] #[macro_use] mod platform; pub use self::platform::*; // liblibc has the wrong decl for linux :| hack until #26809 lands. extern "C" { #[doc(hidden)] pub fn ioctl(fd: libc::c_int, req: libc::c_ulong, ...) -> libc::c_int; } /// A hack to get the macros to work nicely. #[doc(hidden)] pub use ::libc as libc;