|
1 |
| -//! Provide helpers for making ioctl system calls |
2 |
| -//! |
3 |
| -//! Currently supports Linux on all architectures. Other platforms welcome! |
| 1 | +//! Provide helpers for making ioctl system calls. |
4 | 2 | //!
|
5 | 3 | //! This library is pretty low-level and messy. `ioctl` is not fun.
|
6 | 4 | //!
|
|
24 | 22 | //! to the CDROM device.
|
25 | 23 | //! * Do whatever else the device driver creator thought made most sense.
|
26 | 24 | //!
|
27 |
| -//! `ioctl`s are synchronous system calls and are similar to read and |
28 |
| -//! write calls in that regard. |
| 25 | +//! `ioctl`s are synchronous system calls and are similar to read and write calls in that regard. |
| 26 | +//! They operate on file descriptors and have an identifier that specifies what the ioctl is. |
| 27 | +//! Additionally they may read or write data and therefore need to pass along a data pointer. |
| 28 | +//! Besides the semantics of the ioctls being confusing, the generation of this identifer can also |
| 29 | +//! be difficult. |
29 | 30 | //!
|
30 |
| -//! What does this module support? |
31 |
| -//! =============================== |
| 31 | +//! Historically `ioctl` numbers were arbitrary hard-coded values. This changed to a more-ordered |
| 32 | +//! system where the ioctl numbers had various subcomponents: |
| 33 | +//! * Number: The actual ioctl ID |
| 34 | +//! * Type: A grouping of ioctls for a common purpose or driver |
| 35 | +//! * Size: The size in bytes of the data that will be transferred |
| 36 | +//! * Direction: Whether there is any data and if it's read, write, or both |
| 37 | +//! |
| 38 | +//! Newer drivers should not generate complete integer identifiers for their `ioctl`s instead |
| 39 | +//! preferring to use the 4 components above to generate the final ioctl identifier. Because of |
| 40 | +//! how old `ioctl`s are, however, there are many hard-coded `ioctl` identifiers. These are |
| 41 | +//! commonly referred to as "bad" in `ioctl` documentation. |
| 42 | +//! |
| 43 | +//! Defining ioctls |
| 44 | +//! =============== |
32 | 45 | //!
|
33 |
| -//! This library provides the `ioctl!` macro, for binding `ioctl`s. |
34 |
| -//! Here's a few examples of how that can work for SPI under Linux |
35 |
| -//! from [rust-spidev](https://github.com/posborne/rust-spidev). |
| 46 | +//! This library provides the `ioctl!` macro, for binding `ioctl`s. This macro generates unsafe |
| 47 | +//! functions that can then be used for calling the ioctl. This macro has a few different ways it |
| 48 | +//! can be used depending on the specific ioctl you're working with. |
| 49 | +//! |
| 50 | +//! A simple `ioctl` is `SPI_IOC_RD_MODE`. This ioctl works with the SPI interface on Linux. This |
| 51 | +//! specific `ioctl` reads the mode of the SPI mode (one of 4 values, so 2 bits each) as a `u8`. |
| 52 | +//! It's declared in `/include/uapi/linux/spi/spidev.h` as `_IOR(SPI_IOC_MAGIC, 1, __u8)`. We can |
| 53 | +//! therefore generate a function to call this `ioctl` using the `ioctl!` macro in nix like: |
36 | 54 | //!
|
37 | 55 | //! ```
|
38 |
| -//! #[allow(non_camel_case_types)] |
39 |
| -//! pub struct spi_ioc_transfer { |
40 |
| -//! pub tx_buf: u64, |
41 |
| -//! pub rx_buf: u64, |
42 |
| -//! pub len: u32, |
43 |
| -//! |
44 |
| -//! // optional overrides |
45 |
| -//! pub speed_hz: u32, |
46 |
| -//! pub delay_usecs: u16, |
47 |
| -//! pub bits_per_word: u8, |
48 |
| -//! pub cs_change: u8, |
49 |
| -//! pub pad: u32, |
50 |
| -//! } |
| 56 | +//! # #[macro_use] extern crate nix; |
| 57 | +//! # const SPI_IOC_MAGIC: nix::libc::c_int = 'k' as nix::libc::c_int; |
| 58 | +//! ioctl!(read spi_read_mode with SPI_IOC_MAGIC, 1; u8); |
| 59 | +//! # fn main() {} |
| 60 | +//! ``` |
51 | 61 | //!
|
52 |
| -//! #[cfg(linux)] |
53 |
| -//! mod ioctl { |
54 |
| -//! use super::*; |
55 |
| -//! |
56 |
| -//! const SPI_IOC_MAGIC: u8 = 'k' as u8; |
57 |
| -//! const SPI_IOC_NR_TRANSFER: u8 = 0; |
58 |
| -//! const SPI_IOC_NR_MODE: u8 = 1; |
59 |
| -//! const SPI_IOC_NR_LSB_FIRST: u8 = 2; |
60 |
| -//! const SPI_IOC_NR_BITS_PER_WORD: u8 = 3; |
61 |
| -//! const SPI_IOC_NR_MAX_SPEED_HZ: u8 = 4; |
62 |
| -//! const SPI_IOC_NR_MODE32: u8 = 5; |
63 |
| -//! |
64 |
| -//! ioctl!(read get_mode_u8 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u8); |
65 |
| -//! ioctl!(read get_mode_u32 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u32); |
66 |
| -//! ioctl!(write set_mode_u8 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u8); |
67 |
| -//! ioctl!(write set_mode_u32 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE32; u32); |
68 |
| -//! ioctl!(read get_lsb_first with SPI_IOC_MAGIC, SPI_IOC_NR_LSB_FIRST; u8); |
69 |
| -//! ioctl!(write set_lsb_first with SPI_IOC_MAGIC, SPI_IOC_NR_LSB_FIRST; u8); |
70 |
| -//! ioctl!(read get_bits_per_word with SPI_IOC_MAGIC, SPI_IOC_NR_BITS_PER_WORD; u8); |
71 |
| -//! ioctl!(write set_bits_per_word with SPI_IOC_MAGIC, SPI_IOC_NR_BITS_PER_WORD; u8); |
72 |
| -//! ioctl!(read get_max_speed_hz with SPI_IOC_MAGIC, SPI_IOC_NR_MAX_SPEED_HZ; u32); |
73 |
| -//! ioctl!(write set_max_speed_hz with SPI_IOC_MAGIC, SPI_IOC_NR_MAX_SPEED_HZ; u32); |
74 |
| -//! ioctl!(write spidev_transfer with SPI_IOC_MAGIC, SPI_IOC_NR_TRANSFER; spi_ioc_transfer); |
75 |
| -//! ioctl!(write buf spidev_transfer_buf with SPI_IOC_MAGIC, SPI_IOC_NR_TRANSFER; spi_ioc_transfer); |
| 62 | +//! This generates a function like: |
| 63 | +//! |
| 64 | +//! ``` |
| 65 | +//! # #[macro_use] extern crate nix; |
| 66 | +//! # use nix::libc::c_int as c_int; |
| 67 | +//! # use nix::libc::c_ulong as c_ulong; |
| 68 | +//! # use std::mem; |
| 69 | +//! # use nix::{Errno, libc, Result}; |
| 70 | +//! # const SPI_IOC_MAGIC: u8 = 'k' as u8; |
| 71 | +//! pub unsafe fn spi_read_mode(fd: c_int, val: *mut u8) -> Result<c_int> { |
| 72 | +//! let res = libc::ioctl(fd, ior!(SPI_IOC_MAGIC, 1, mem::size_of::<u8>()), val); |
| 73 | +//! Errno::result(res) |
76 | 74 | //! }
|
| 75 | +//! # fn main() {} |
| 76 | +//! ``` |
| 77 | +//! |
| 78 | +//! The return value for `ioctl` functions generated by the `ioctl!` macro are assumed to return -1 |
| 79 | +//! on error and everything else is a valid return value. If the return value needs to be changed, |
| 80 | +//! you can use `Result::map` on the return value in a helper function. |
77 | 81 | //!
|
78 |
| -//! // doctest workaround |
79 |
| -//! fn main() {} |
| 82 | +//! There are equivalent forms for `write`, `none` (no data in or out), and `readwrite`. The mode |
| 83 | +//! for a given `ioctl` should be clear from the documentation if it has good documentation. |
| 84 | +//! Otherwise it will be clear based on the macro used to generate the `ioctl` number where |
| 85 | +//! `_IOC`, _IOR`, `_IOW`, and `_IORW` map to "none", "read", "write", and "readwrite" |
| 86 | +//! respectively. |
| 87 | +//! |
| 88 | +//! Some `ioctl`s can operate on arrays of objects, so there are `read buf`, `write buf`, and |
| 89 | +//! `readwrite buf` forms as well. These generate functions that include a `len` argument to |
| 90 | +//! specify the length of the array: |
| 91 | +//! |
| 92 | +//! ```text |
| 93 | +//! pub unsafe fn $NAME(fd: c_int, val: *mut u8, len: usize) -> Result<c_int>; |
80 | 94 | //! ```
|
81 | 95 | //!
|
82 |
| -//! Spidev uses the `_IOC` macros that are encouraged (as far as |
83 |
| -//! `ioctl` can be encouraged at all) for newer drivers. Many |
84 |
| -//! drivers, however, just use magic numbers with no attached |
85 |
| -//! semantics. For those, the `ioctl!(bad ...)` variant should be |
86 |
| -//! used (the "bad" terminology is from the Linux kernel). |
| 96 | +//! As mentioned earlier, there are many old `ioctl`s that do not use the newer method of |
| 97 | +//! generating `ioctl` numbers and instead use hardcoded values. These can be used with the `bad` |
| 98 | +//! form of the `ioctl!` macro (there is no data transfer direction used with `bad`). The naming of |
| 99 | +//! this comes from the Linux kernel which refers to these `ioctl`s as "bad". |
| 100 | +//! |
| 101 | +//! For example the `TCGETS` `ioctl` reads a `termios` data structure for a given file descriptor. |
| 102 | +//! It can be implemented as: |
| 103 | +//! |
| 104 | +//! ``` |
| 105 | +//! # #[macro_use] extern crate nix; |
| 106 | +//! # #[cfg(any(target_os = "android", target_os = "linux"))] |
| 107 | +//! # use nix::libc::TCGETS as TCGETS; |
| 108 | +//! # #[cfg(any(target_os = "android", target_os = "linux"))] |
| 109 | +//! ioctl!(bad tcgets with TCGETS); |
| 110 | +//! # fn main() {} |
| 111 | +//! ``` |
| 112 | +//! |
| 113 | +//! The generated function has the same form as that generated by `read`: |
| 114 | +//! |
| 115 | +//! ```text |
| 116 | +//! pub unsafe fn tcgets(fd: c_int, val: *mut u8) -> Result<c_int>; |
| 117 | +//! ``` |
| 118 | +//! |
| 119 | +//! There is also a `bad none` form for use with hard-coded `ioctl`s that do not transfer data. |
| 120 | +//! The `TIOCEXCL` `ioctl` that's part of the termios API can be implemented as: |
| 121 | +//! |
| 122 | +//! ``` |
| 123 | +//! # #[macro_use] extern crate nix; |
| 124 | +//! # use nix::libc::TIOCEXCL as TIOCEXCL; |
| 125 | +//! ioctl!(bad none tiocexcl with TIOCEXCL); |
| 126 | +//! # fn main() {} |
| 127 | +//! ``` |
| 128 | +//! |
| 129 | +//! More examples on using `ioctl!` can be found in the [rust-spidev crate](https://github.com/posborne/rust-spidev). |
87 | 130 | //!
|
88 | 131 | //! How do I get the magic numbers?
|
89 | 132 | //! ===============================
|
90 | 133 | //!
|
91 | 134 | //! For Linux, look at your system's headers. For example, `/usr/include/linux/input.h` has a lot
|
92 |
| -//! of lines defining macros which use `_IOR`, `_IOW`, `_IOC`, and `_IORW`. These macros |
93 |
| -//! correspond to the `ior!`, `iow!`, `ioc!`, and `iorw!` macros defined in this crate. |
94 |
| -//! Additionally, there is the `ioctl!` macro for creating a wrapper around `ioctl` that is |
95 |
| -//! somewhat more type-safe. |
96 |
| -//! |
97 |
| -//! Most `ioctl`s have no or little documentation. You'll need to scrounge through |
98 |
| -//! the source to figure out what they do and how they should be used. |
99 |
| -//! |
| 135 | +//! of lines defining macros which use `_IOR`, `_IOW`, `_IOC`, and `_IORW`. Finding documentation |
| 136 | +//! on some of those `ioctl`s can be trickier, however, though some are documented in the manpages |
| 137 | +//! and others are documented directly in the source. |
100 | 138 | #[cfg(any(target_os = "linux", target_os = "android"))]
|
101 | 139 | #[path = "platform/linux.rs"]
|
102 | 140 | #[macro_use]
|
|
0 commit comments