1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 //! Macros and wrapper functions for dealing with ioctls.
6
7 use std::os::raw::*;
8 use std::os::unix::io::AsRawFd;
9
10 use libc;
11
12 /// Raw macro to declare the expression that calculates an ioctl number
13 #[macro_export]
14 macro_rules! ioctl_expr {
15 ($dir:expr, $ty:expr, $nr:expr, $size:expr) => {
16 (($dir << $crate::ioctl::_IOC_DIRSHIFT)
17 | ($ty << $crate::ioctl::_IOC_TYPESHIFT)
18 | ($nr << $crate::ioctl::_IOC_NRSHIFT)
19 | ($size << $crate::ioctl::_IOC_SIZESHIFT)) as ::std::os::raw::c_ulong
20 };
21 }
22
23 /// Raw macro to declare a function that returns an ioctl number.
24 #[macro_export]
25 macro_rules! ioctl_ioc_nr {
26 ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr) => {
27 #[allow(non_snake_case)]
28 pub fn $name() -> ::std::os::raw::c_ulong {
29 $crate::ioctl_expr!($dir, $ty, $nr, $size)
30 }
31 };
32 ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr, $($v:ident),+) => {
33 #[allow(non_snake_case)]
34 pub fn $name($($v: ::std::os::raw::c_uint),+) -> ::std::os::raw::c_ulong {
35 $crate::ioctl_expr!($dir, $ty, $nr, $size)
36 }
37 };
38 }
39
40 /// Declare an ioctl that transfers no data.
41 #[macro_export]
42 macro_rules! ioctl_io_nr {
43 ($name:ident, $ty:expr, $nr:expr) => {
44 $crate::ioctl_ioc_nr!($name, $crate::ioctl::_IOC_NONE, $ty, $nr, 0);
45 };
46 ($name:ident, $ty:expr, $nr:expr, $($v:ident),+) => {
47 $crate::ioctl_ioc_nr!($name, $crate::ioctl::_IOC_NONE, $ty, $nr, 0, $($v),+);
48 };
49 }
50
51 /// Declare an ioctl that reads data.
52 #[macro_export]
53 macro_rules! ioctl_ior_nr {
54 ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
55 $crate::ioctl_ioc_nr!(
56 $name,
57 $crate::ioctl::_IOC_READ,
58 $ty,
59 $nr,
60 ::std::mem::size_of::<$size>() as u32
61 );
62 };
63 ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
64 $crate::ioctl_ioc_nr!(
65 $name,
66 $crate::ioctl::_IOC_READ,
67 $ty,
68 $nr,
69 ::std::mem::size_of::<$size>() as u32,
70 $($v),+
71 );
72 };
73 }
74
75 /// Declare an ioctl that writes data.
76 #[macro_export]
77 macro_rules! ioctl_iow_nr {
78 ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
79 $crate::ioctl_ioc_nr!(
80 $name,
81 $crate::ioctl::_IOC_WRITE,
82 $ty,
83 $nr,
84 ::std::mem::size_of::<$size>() as u32
85 );
86 };
87 ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
88 $crate::ioctl_ioc_nr!(
89 $name,
90 $crate::ioctl::_IOC_WRITE,
91 $ty,
92 $nr,
93 ::std::mem::size_of::<$size>() as u32,
94 $($v),+
95 );
96 };
97 }
98
99 /// Declare an ioctl that reads and writes data.
100 #[macro_export]
101 macro_rules! ioctl_iowr_nr {
102 ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
103 $crate::ioctl_ioc_nr!(
104 $name,
105 $crate::ioctl::_IOC_READ | $crate::ioctl::_IOC_WRITE,
106 $ty,
107 $nr,
108 ::std::mem::size_of::<$size>() as u32
109 );
110 };
111 ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
112 $crate::ioctl_ioc_nr!(
113 $name,
114 $crate::ioctl::_IOC_READ | $crate::ioctl::_IOC_WRITE,
115 $ty,
116 $nr,
117 ::std::mem::size_of::<$size>() as u32,
118 $($v),+
119 );
120 };
121 }
122
123 pub const _IOC_NRBITS: c_uint = 8;
124 pub const _IOC_TYPEBITS: c_uint = 8;
125 pub const _IOC_SIZEBITS: c_uint = 14;
126 pub const _IOC_DIRBITS: c_uint = 2;
127 pub const _IOC_NRMASK: c_uint = 255;
128 pub const _IOC_TYPEMASK: c_uint = 255;
129 pub const _IOC_SIZEMASK: c_uint = 16383;
130 pub const _IOC_DIRMASK: c_uint = 3;
131 pub const _IOC_NRSHIFT: c_uint = 0;
132 pub const _IOC_TYPESHIFT: c_uint = 8;
133 pub const _IOC_SIZESHIFT: c_uint = 16;
134 pub const _IOC_DIRSHIFT: c_uint = 30;
135 pub const _IOC_NONE: c_uint = 0;
136 pub const _IOC_WRITE: c_uint = 1;
137 pub const _IOC_READ: c_uint = 2;
138 pub const IOC_IN: c_uint = 1_073_741_824;
139 pub const IOC_OUT: c_uint = 2_147_483_648;
140 pub const IOC_INOUT: c_uint = 3_221_225_472;
141 pub const IOCSIZE_MASK: c_uint = 1_073_676_288;
142 pub const IOCSIZE_SHIFT: c_uint = 16;
143
144 /// Run an ioctl with no arguments.
ioctl<F: AsRawFd>(fd: &F, nr: c_ulong) -> c_int145 pub unsafe fn ioctl<F: AsRawFd>(fd: &F, nr: c_ulong) -> c_int {
146 libc::ioctl(fd.as_raw_fd(), nr, 0)
147 }
148
149 /// Run an ioctl with a single value argument.
ioctl_with_val<F: AsRawFd>(fd: &F, nr: c_ulong, arg: c_ulong) -> c_int150 pub unsafe fn ioctl_with_val<F: AsRawFd>(fd: &F, nr: c_ulong, arg: c_ulong) -> c_int {
151 libc::ioctl(fd.as_raw_fd(), nr, arg)
152 }
153
154 /// Run an ioctl with an immutable reference.
ioctl_with_ref<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: &T) -> c_int155 pub unsafe fn ioctl_with_ref<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: &T) -> c_int {
156 libc::ioctl(fd.as_raw_fd(), nr, arg as *const T as *const c_void)
157 }
158
159 /// Run an ioctl with a mutable reference.
ioctl_with_mut_ref<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: &mut T) -> c_int160 pub unsafe fn ioctl_with_mut_ref<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: &mut T) -> c_int {
161 libc::ioctl(fd.as_raw_fd(), nr, arg as *mut T as *mut c_void)
162 }
163
164 /// Run an ioctl with a raw pointer.
ioctl_with_ptr<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: *const T) -> c_int165 pub unsafe fn ioctl_with_ptr<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: *const T) -> c_int {
166 libc::ioctl(fd.as_raw_fd(), nr, arg as *const c_void)
167 }
168
169 /// Run an ioctl with a mutable raw pointer.
ioctl_with_mut_ptr<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: *mut T) -> c_int170 pub unsafe fn ioctl_with_mut_ptr<F: AsRawFd, T>(fd: &F, nr: c_ulong, arg: *mut T) -> c_int {
171 libc::ioctl(fd.as_raw_fd(), nr, arg as *mut c_void)
172 }
173
174 #[cfg(test)]
175 mod tests {
176 const TUNTAP: ::std::os::raw::c_uint = 0x54;
177 const VHOST: ::std::os::raw::c_uint = 0xaf;
178 const EVDEV: ::std::os::raw::c_uint = 0x45;
179
180 ioctl_io_nr!(VHOST_SET_OWNER, VHOST, 0x01);
181 ioctl_ior_nr!(TUNGETFEATURES, TUNTAP, 0xcf, ::std::os::raw::c_uint);
182 ioctl_iow_nr!(TUNSETQUEUE, TUNTAP, 0xd9, ::std::os::raw::c_int);
183 ioctl_iowr_nr!(VHOST_GET_VRING_BASE, VHOST, 0x12, ::std::os::raw::c_int);
184
185 ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, [u8; 128], evt);
186 ioctl_io_nr!(FAKE_IOCTL_2_ARG, EVDEV, 0x01 + x + y, x, y);
187
188 #[test]
ioctl_macros()189 fn ioctl_macros() {
190 assert_eq!(0x0000af01, VHOST_SET_OWNER());
191 assert_eq!(0x800454cf, TUNGETFEATURES());
192 assert_eq!(0x400454d9, TUNSETQUEUE());
193 assert_eq!(0xc004af12, VHOST_GET_VRING_BASE());
194
195 assert_eq!(0x80804522, EVIOCGBIT(2));
196 assert_eq!(0x00004509, FAKE_IOCTL_2_ARG(3, 5));
197 }
198 }
199