1#![allow(dead_code)]
2
3// Simple tests to ensure macro generated fns compile
4ioctl_none_bad!(do_bad, 0x1234);
5ioctl_read_bad!(do_bad_read, 0x1234, u16);
6ioctl_write_int_bad!(do_bad_write_int, 0x1234);
7ioctl_write_ptr_bad!(do_bad_write_ptr, 0x1234, u8);
8ioctl_readwrite_bad!(do_bad_readwrite, 0x1234, u32);
9ioctl_none!(do_none, 0, 0);
10ioctl_read!(read_test, 0, 0, u32);
11ioctl_write_int!(write_ptr_int, 0, 0);
12ioctl_write_ptr!(write_ptr_u8, 0, 0, u8);
13ioctl_write_ptr!(write_ptr_u32, 0, 0, u32);
14ioctl_write_ptr!(write_ptr_u64, 0, 0, u64);
15ioctl_readwrite!(readwrite_test, 0, 0, u64);
16ioctl_read_buf!(readbuf_test, 0, 0, u32);
17const SPI_IOC_MAGIC: u8 = b'k';
18const SPI_IOC_MESSAGE: u8 = 0;
19ioctl_write_buf!(writebuf_test_consts, SPI_IOC_MAGIC, SPI_IOC_MESSAGE, u8);
20ioctl_write_buf!(writebuf_test_u8, 0, 0, u8);
21ioctl_write_buf!(writebuf_test_u32, 0, 0, u32);
22ioctl_write_buf!(writebuf_test_u64, 0, 0, u64);
23ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32);
24
25// See C code for source of values for op calculations (does NOT work for mips/powerpc):
26// https://gist.github.com/posborne/83ea6880770a1aef332e
27//
28// TODO: Need a way to compute these constants at test time. Using precomputed
29// values is fragile and needs to be maintained.
30
31#[cfg(any(target_os = "linux", target_os = "android"))]
32mod linux {
33 // The cast is not unnecessary on all platforms.
34 #[allow(clippy::unnecessary_cast)]
35 #[test]
36 fn test_op_none() {
37 if cfg!(any(
38 target_arch = "mips",
39 target_arch = "mips64",
40 target_arch = "powerpc",
41 target_arch = "powerpc64"
42 )) {
43 assert_eq!(request_code_none!(b'q', 10) as u32, 0x2000_710A);
44 assert_eq!(request_code_none!(b'a', 255) as u32, 0x2000_61FF);
45 } else {
46 assert_eq!(request_code_none!(b'q', 10) as u32, 0x0000_710A);
47 assert_eq!(request_code_none!(b'a', 255) as u32, 0x0000_61FF);
48 }
49 }
50
51 // The cast is not unnecessary on all platforms.
52 #[allow(clippy::unnecessary_cast)]
53 #[test]
54 fn test_op_write() {
55 if cfg!(any(
56 target_arch = "mips",
57 target_arch = "mips64",
58 target_arch = "powerpc",
59 target_arch = "powerpc64"
60 )) {
61 assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x8001_7A0A);
62 assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x8200_7A0A);
63 } else {
64 assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x4001_7A0A);
65 assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x4200_7A0A);
66 }
67 }
68
69 #[cfg(target_pointer_width = "64")]
70 #[test]
71 fn test_op_write_64() {
72 if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) {
73 assert_eq!(
74 request_code_write!(b'z', 10, 1u64 << 32) as u32,
75 0x8000_7A0A
76 );
77 } else {
78 assert_eq!(
79 request_code_write!(b'z', 10, 1u64 << 32) as u32,
80 0x4000_7A0A
81 );
82 }
83 }
84
85 // The cast is not unnecessary on all platforms.
86 #[allow(clippy::unnecessary_cast)]
87 #[test]
88 fn test_op_read() {
89 if cfg!(any(
90 target_arch = "mips",
91 target_arch = "mips64",
92 target_arch = "powerpc",
93 target_arch = "powerpc64"
94 )) {
95 assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x4001_7A0A);
96 assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x4200_7A0A);
97 } else {
98 assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x8001_7A0A);
99 assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x8200_7A0A);
100 }
101 }
102
103 #[cfg(target_pointer_width = "64")]
104 #[test]
105 fn test_op_read_64() {
106 if cfg!(any(target_arch = "mips64", target_arch = "powerpc64")) {
107 assert_eq!(
108 request_code_read!(b'z', 10, 1u64 << 32) as u32,
109 0x4000_7A0A
110 );
111 } else {
112 assert_eq!(
113 request_code_read!(b'z', 10, 1u64 << 32) as u32,
114 0x8000_7A0A
115 );
116 }
117 }
118
119 // The cast is not unnecessary on all platforms.
120 #[allow(clippy::unnecessary_cast)]
121 #[test]
122 fn test_op_read_write() {
123 assert_eq!(request_code_readwrite!(b'z', 10, 1) as u32, 0xC001_7A0A);
124 assert_eq!(request_code_readwrite!(b'z', 10, 512) as u32, 0xC200_7A0A);
125 }
126
127 #[cfg(target_pointer_width = "64")]
128 #[test]
129 fn test_op_read_write_64() {
130 assert_eq!(
131 request_code_readwrite!(b'z', 10, 1u64 << 32) as u32,
132 0xC000_7A0A
133 );
134 }
135}
136
137#[cfg(any(
138 target_os = "dragonfly",
139 target_os = "freebsd",
140 target_os = "ios",
141 target_os = "macos",
142 target_os = "netbsd",
143 target_os = "openbsd"
144))]
145mod bsd {
146 #[test]
147 fn test_op_none() {
148 assert_eq!(request_code_none!(b'q', 10), 0x2000_710A);
149 assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
150 }
151
152 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
153 #[test]
154 fn test_op_write_int() {
155 assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604);
156 assert_eq!(request_code_write_int!(b'p', 2), 0x2004_7002);
157 }
158
159 #[test]
160 fn test_op_write() {
161 assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A);
162 assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A);
163 }
164
165 #[cfg(target_pointer_width = "64")]
166 #[test]
167 fn test_op_write_64() {
168 assert_eq!(request_code_write!(b'z', 10, 1u64 << 32), 0x8000_7A0A);
169 }
170
171 #[test]
172 fn test_op_read() {
173 assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A);
174 assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A);
175 }
176
177 #[cfg(target_pointer_width = "64")]
178 #[test]
179 fn test_op_read_64() {
180 assert_eq!(request_code_read!(b'z', 10, 1u64 << 32), 0x4000_7A0A);
181 }
182
183 #[test]
184 fn test_op_read_write() {
185 assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A);
186 assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A);
187 }
188
189 #[cfg(target_pointer_width = "64")]
190 #[test]
191 fn test_op_read_write_64() {
192 assert_eq!(request_code_readwrite!(b'z', 10, 1u64 << 32), 0xC000_7A0A);
193 }
194}
195
196#[cfg(any(target_os = "android", target_os = "linux"))]
197mod linux_ioctls {
198 use std::mem;
199 use std::os::unix::io::AsRawFd;
200
201 use libc::{termios, TCGETS, TCSBRK, TCSETS, TIOCNXCL};
202 use tempfile::tempfile;
203
204 use nix::errno::Errno;
205
206 ioctl_none_bad!(tiocnxcl, TIOCNXCL);
207 #[test]
208 fn test_ioctl_none_bad() {
209 let file = tempfile().unwrap();
210 let res = unsafe { tiocnxcl(file.as_raw_fd()) };
211 assert_eq!(res, Err(Errno::ENOTTY));
212 }
213
214 ioctl_read_bad!(tcgets, TCGETS, termios);
215 #[test]
216 fn test_ioctl_read_bad() {
217 let file = tempfile().unwrap();
218 let mut termios = unsafe { mem::zeroed() };
219 let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) };
220 assert_eq!(res, Err(Errno::ENOTTY));
221 }
222
223 ioctl_write_int_bad!(tcsbrk, TCSBRK);
224 #[test]
225 fn test_ioctl_write_int_bad() {
226 let file = tempfile().unwrap();
227 let res = unsafe { tcsbrk(file.as_raw_fd(), 0) };
228 assert_eq!(res, Err(Errno::ENOTTY));
229 }
230
231 ioctl_write_ptr_bad!(tcsets, TCSETS, termios);
232 #[test]
233 fn test_ioctl_write_ptr_bad() {
234 let file = tempfile().unwrap();
235 let termios: termios = unsafe { mem::zeroed() };
236 let res = unsafe { tcsets(file.as_raw_fd(), &termios) };
237 assert_eq!(res, Err(Errno::ENOTTY));
238 }
239
240 // FIXME: Find a suitable example for `ioctl_readwrite_bad`
241
242 // From linux/videodev2.h
243 ioctl_none!(log_status, b'V', 70);
244 #[test]
245 fn test_ioctl_none() {
246 let file = tempfile().unwrap();
247 let res = unsafe { log_status(file.as_raw_fd()) };
248 assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
249 }
250
251 #[repr(C)]
252 pub struct v4l2_audio {
253 index: u32,
254 name: [u8; 32],
255 capability: u32,
256 mode: u32,
257 reserved: [u32; 2],
258 }
259
260 // From linux/videodev2.h
261 ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio);
262 #[test]
263 fn test_ioctl_write_ptr() {
264 let file = tempfile().unwrap();
265 let data: v4l2_audio = unsafe { mem::zeroed() };
266 let res = unsafe { s_audio(file.as_raw_fd(), &data) };
267 assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
268 }
269
270 // From linux/net/bluetooth/hci_sock.h
271 const HCI_IOC_MAGIC: u8 = b'H';
272 const HCI_IOC_HCIDEVUP: u8 = 201;
273 ioctl_write_int!(hcidevup, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
274 #[test]
275 fn test_ioctl_write_int() {
276 let file = tempfile().unwrap();
277 let res = unsafe { hcidevup(file.as_raw_fd(), 0) };
278 assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
279 }
280
281 // From linux/videodev2.h
282 ioctl_read!(g_audio, b'V', 33, v4l2_audio);
283 #[test]
284 fn test_ioctl_read() {
285 let file = tempfile().unwrap();
286 let mut data: v4l2_audio = unsafe { mem::zeroed() };
287 let res = unsafe { g_audio(file.as_raw_fd(), &mut data) };
288 assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
289 }
290
291 // From linux/videodev2.h
292 ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio);
293 #[test]
294 fn test_ioctl_readwrite() {
295 let file = tempfile().unwrap();
296 let mut data: v4l2_audio = unsafe { mem::zeroed() };
297 let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) };
298 assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
299 }
300
301 // FIXME: Find a suitable example for `ioctl_read_buf`.
302
303 #[repr(C)]
304 pub struct spi_ioc_transfer {
305 tx_buf: u64,
306 rx_buf: u64,
307 len: u32,
308 speed_hz: u32,
309 delay_usecs: u16,
310 bits_per_word: u8,
311 cs_change: u8,
312 tx_nbits: u8,
313 rx_nbits: u8,
314 pad: u16,
315 }
316
317 // From linux/spi/spidev.h
318 ioctl_write_buf!(
319 spi_ioc_message,
320 super::SPI_IOC_MAGIC,
321 super::SPI_IOC_MESSAGE,
322 spi_ioc_transfer
323 );
324 #[test]
325 fn test_ioctl_write_buf() {
326 let file = tempfile().unwrap();
327 let data: [spi_ioc_transfer; 4] = unsafe { mem::zeroed() };
328 let res = unsafe { spi_ioc_message(file.as_raw_fd(), &data[..]) };
329 assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
330 }
331
332 // FIXME: Find a suitable example for `ioctl_readwrite_buf`.
333}
334
335#[cfg(target_os = "freebsd")]
336mod freebsd_ioctls {
337 use std::mem;
338 use std::os::unix::io::AsRawFd;
339
340 use libc::termios;
341 use tempfile::tempfile;
342
343 use nix::errno::Errno;
344
345 // From sys/sys/ttycom.h
346 const TTY_IOC_MAGIC: u8 = b't';
347 const TTY_IOC_TYPE_NXCL: u8 = 14;
348 const TTY_IOC_TYPE_GETA: u8 = 19;
349 const TTY_IOC_TYPE_SETA: u8 = 20;
350
351 ioctl_none!(tiocnxcl, TTY_IOC_MAGIC, TTY_IOC_TYPE_NXCL);
352 #[test]
353 fn test_ioctl_none() {
354 let file = tempfile().unwrap();
355 let res = unsafe { tiocnxcl(file.as_raw_fd()) };
356 assert_eq!(res, Err(Errno::ENOTTY));
357 }
358
359 ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios);
360 #[test]
361 fn test_ioctl_read() {
362 let file = tempfile().unwrap();
363 let mut termios = unsafe { mem::zeroed() };
364 let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) };
365 assert_eq!(res, Err(Errno::ENOTTY));
366 }
367
368 ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios);
369 #[test]
370 fn test_ioctl_write_ptr() {
371 let file = tempfile().unwrap();
372 let termios: termios = unsafe { mem::zeroed() };
373 let res = unsafe { tiocseta(file.as_raw_fd(), &termios) };
374 assert_eq!(res, Err(Errno::ENOTTY));
375 }
376}
377