1 use cfg_if::cfg_if;
2 
3 /// The datatype used for the ioctl number
4 #[cfg(any(target_os = "android", target_env = "musl"))]
5 #[doc(hidden)]
6 pub type ioctl_num_type = ::libc::c_int;
7 #[cfg(not(any(target_os = "android", target_env = "musl")))]
8 #[doc(hidden)]
9 pub type ioctl_num_type = ::libc::c_ulong;
10 /// The datatype used for the 3rd argument
11 #[doc(hidden)]
12 pub type ioctl_param_type = ::libc::c_ulong;
13 
14 #[doc(hidden)]
15 pub const NRBITS: ioctl_num_type = 8;
16 #[doc(hidden)]
17 pub const TYPEBITS: ioctl_num_type = 8;
18 
19 cfg_if! {
20     if #[cfg(any(
21         target_arch = "mips",
22         target_arch = "mips32r6",
23         target_arch = "mips64",
24         target_arch = "mips64r6",
25         target_arch = "powerpc",
26         target_arch = "powerpc64",
27         target_arch = "sparc64"
28     ))] {
29         mod consts {
30             #[doc(hidden)]
31             pub const NONE: u8 = 1;
32             #[doc(hidden)]
33             pub const READ: u8 = 2;
34             #[doc(hidden)]
35             pub const WRITE: u8 = 4;
36             #[doc(hidden)]
37             pub const SIZEBITS: u8 = 13;
38             #[doc(hidden)]
39             pub const DIRBITS: u8 = 3;
40         }
41     } else {
42         // "Generic" ioctl protocol
43         mod consts {
44             #[doc(hidden)]
45             pub const NONE: u8 = 0;
46             #[doc(hidden)]
47             pub const READ: u8 = 2;
48             #[doc(hidden)]
49             pub const WRITE: u8 = 1;
50             #[doc(hidden)]
51             pub const SIZEBITS: u8 = 14;
52             #[doc(hidden)]
53             pub const DIRBITS: u8 = 2;
54         }
55     }
56 }
57 
58 pub use self::consts::*;
59 
60 #[doc(hidden)]
61 pub const NRSHIFT: ioctl_num_type = 0;
62 #[doc(hidden)]
63 pub const TYPESHIFT: ioctl_num_type = NRSHIFT + NRBITS as ioctl_num_type;
64 #[doc(hidden)]
65 pub const SIZESHIFT: ioctl_num_type = TYPESHIFT + TYPEBITS as ioctl_num_type;
66 #[doc(hidden)]
67 pub const DIRSHIFT: ioctl_num_type = SIZESHIFT + SIZEBITS as ioctl_num_type;
68 
69 #[doc(hidden)]
70 pub const NRMASK: ioctl_num_type = (1 << NRBITS) - 1;
71 #[doc(hidden)]
72 pub const TYPEMASK: ioctl_num_type = (1 << TYPEBITS) - 1;
73 #[doc(hidden)]
74 pub const SIZEMASK: ioctl_num_type = (1 << SIZEBITS) - 1;
75 #[doc(hidden)]
76 pub const DIRMASK: ioctl_num_type = (1 << DIRBITS) - 1;
77 
78 /// Encode an ioctl command.
79 #[macro_export]
80 #[doc(hidden)]
81 macro_rules! ioc {
82     ($dir:expr, $ty:expr, $nr:expr, $sz:expr) => {
83         (($dir as $crate::sys::ioctl::ioctl_num_type
84             & $crate::sys::ioctl::DIRMASK)
85             << $crate::sys::ioctl::DIRSHIFT)
86             | (($ty as $crate::sys::ioctl::ioctl_num_type
87                 & $crate::sys::ioctl::TYPEMASK)
88                 << $crate::sys::ioctl::TYPESHIFT)
89             | (($nr as $crate::sys::ioctl::ioctl_num_type
90                 & $crate::sys::ioctl::NRMASK)
91                 << $crate::sys::ioctl::NRSHIFT)
92             | (($sz as $crate::sys::ioctl::ioctl_num_type
93                 & $crate::sys::ioctl::SIZEMASK)
94                 << $crate::sys::ioctl::SIZESHIFT)
95     };
96 }
97 
98 /// Generate an ioctl request code for a command that passes no data.
99 ///
100 /// This is equivalent to the `_IO()` macro exposed by the C ioctl API.
101 ///
102 /// You should only use this macro directly if the `ioctl` you're working
103 /// with is "bad" and you cannot use `ioctl_none!()` directly.
104 ///
105 /// # Example
106 ///
107 /// ```
108 /// # #[macro_use] extern crate nix;
109 /// const KVMIO: u8 = 0xAE;
110 /// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
111 /// # fn main() {}
112 /// ```
113 #[macro_export(local_inner_macros)]
114 macro_rules! request_code_none {
115     ($ty:expr, $nr:expr) => {
116         ioc!($crate::sys::ioctl::NONE, $ty, $nr, 0)
117     };
118 }
119 
120 /// Generate an ioctl request code for a command that reads.
121 ///
122 /// This is equivalent to the `_IOR()` macro exposed by the C ioctl API.
123 ///
124 /// You should only use this macro directly if the `ioctl` you're working
125 /// with is "bad" and you cannot use `ioctl_read!()` directly.
126 ///
127 /// The read/write direction is relative to userland, so this
128 /// command would be userland is reading and the kernel is
129 /// writing.
130 #[macro_export(local_inner_macros)]
131 macro_rules! request_code_read {
132     ($ty:expr, $nr:expr, $sz:expr) => {
133         ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz)
134     };
135 }
136 
137 /// Generate an ioctl request code for a command that writes.
138 ///
139 /// This is equivalent to the `_IOW()` macro exposed by the C ioctl API.
140 ///
141 /// You should only use this macro directly if the `ioctl` you're working
142 /// with is "bad" and you cannot use `ioctl_write!()` directly.
143 ///
144 /// The read/write direction is relative to userland, so this
145 /// command would be userland is writing and the kernel is
146 /// reading.
147 #[macro_export(local_inner_macros)]
148 macro_rules! request_code_write {
149     ($ty:expr, $nr:expr, $sz:expr) => {
150         ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz)
151     };
152 }
153 
154 /// Generate an ioctl request code for a command that reads and writes.
155 ///
156 /// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API.
157 ///
158 /// You should only use this macro directly if the `ioctl` you're working
159 /// with is "bad" and you cannot use `ioctl_readwrite!()` directly.
160 #[macro_export(local_inner_macros)]
161 macro_rules! request_code_readwrite {
162     ($ty:expr, $nr:expr, $sz:expr) => {
163         ioc!(
164             $crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE,
165             $ty,
166             $nr,
167             $sz
168         )
169     };
170 }
171