use std::mem::size_of;
const IOC_NONN: u32 = 0;
const IOC_WRITE: u32 = 1;
const IOC_READ: u32 = 2;
const IOC_NRSHIFT: usize = 0;
const IOC_TYPESHIFT: usize = 8;
const IOC_SIZESHIFT: usize = 16;
const IOC_DIRSHIFT: usize = 30;
const fn ioctl_ioc(dir: u32, type_: u8, nr: u8, size: u32) -> u32 {
(dir << IOC_DIRSHIFT)
| (size << IOC_SIZESHIFT)
| ((type_ as u32) << IOC_TYPESHIFT)
| ((nr as u32) << IOC_NRSHIFT)
}
pub const fn ioctl_io(type_: u8, nr: u8) -> u32 {
ioctl_ioc(IOC_NONN, type_, nr, 0)
}
pub const fn ioctl_ior<T>(type_: u8, nr: u8) -> u32 {
ioctl_ioc(IOC_READ, type_, nr, size_of::<T>() as u32)
}
pub const fn ioctl_iow<T>(type_: u8, nr: u8) -> u32 {
ioctl_ioc(IOC_WRITE, type_, nr, size_of::<T>() as u32)
}
pub const fn ioctl_iowr<T>(type_: u8, nr: u8) -> u32 {
ioctl_ioc(IOC_WRITE | IOC_READ, type_, nr, size_of::<T>() as u32)
}
#[macro_export]
macro_rules! ioctl_none {
($name:ident, $type_:expr, $nr:expr) => {
#[allow(clippy::missing_safety_doc)]
pub unsafe fn $name<F: ::std::os::fd::AsFd>(fd: &F) -> ::std::io::Result<libc::c_int> {
let op = $crate::sys::ioctl::ioctl_io($type_, $nr);
$crate::ffi!(unsafe {
::libc::ioctl(::std::os::fd::AsRawFd::as_raw_fd(&fd.as_fd()), op as _, 0)
})
}
};
}
#[macro_export]
macro_rules! ioctl_write_val {
($name:ident, $code:expr, $ty:ty) => {
#[allow(clippy::missing_safety_doc)]
pub unsafe fn $name<F: ::std::os::fd::AsFd>(
fd: &F,
val: $ty,
) -> ::std::io::Result<libc::c_int> {
let op = $code;
$crate::ffi!(unsafe {
::libc::ioctl(::std::os::fd::AsRawFd::as_raw_fd(&fd.as_fd()), op as _, val)
})
}
};
($name:ident, $type_:expr, $nr:expr, $ty:ty) => {
$crate::ioctl_write_val!($name, $crate::sys::ioctl::ioctl_io($type_, $nr), $ty);
};
}
#[macro_export]
macro_rules! ioctl_write_ptr {
($name:ident, $code:expr, $ty:ty) => {
#[allow(clippy::missing_safety_doc)]
pub unsafe fn $name<F: ::std::os::fd::AsFd>(
fd: &F,
val: &$ty,
) -> ::std::io::Result<libc::c_int> {
let op = $code;
$crate::ffi!(unsafe {
::libc::ioctl(
::std::os::fd::AsRawFd::as_raw_fd(&fd.as_fd()),
op as _,
val as *const $ty,
)
})
}
};
($name:ident, $type_:expr, $nr:expr, $ty:ty) => {
$crate::ioctl_write_ptr!(
$name,
$crate::sys::ioctl::ioctl_iow::<$ty>($type_, $nr),
$ty
);
};
}
#[macro_export]
macro_rules! ioctl_write_buf {
($name:ident, $code:expr, $ty:ident) => {
#[allow(clippy::missing_safety_doc)]
pub unsafe fn $name<F: ::std::os::fd::AsFd, const N: usize>(
fd: &F,
val: &$ty<N>,
) -> ::std::io::Result<libc::c_int> {
let op = $code;
$crate::ffi!(unsafe {
::libc::ioctl(
::std::os::fd::AsRawFd::as_raw_fd(&fd.as_fd()),
op as _,
val as *const $ty<N>,
)
})
}
};
($name:ident, $type_:expr, $nr:expr, $ty:ident) => {
$crate::ioctl_write_buf!(
$name,
$crate::sys::ioctl::ioctl_iow::<$ty<0>>($type_, $nr),
$ty
);
};
}
#[macro_export]
macro_rules! ioctl_writeread {
($name:ident, $code:expr, $ty:ty) => {
#[allow(clippy::missing_safety_doc)]
pub unsafe fn $name<F: ::std::os::fd::AsFd>(
fd: &F,
val: &mut $ty,
) -> ::std::io::Result<libc::c_int> {
let op = $code;
$crate::ffi!(unsafe {
::libc::ioctl(
::std::os::fd::AsRawFd::as_raw_fd(&fd.as_fd()),
op as _,
val as *mut $ty,
)
})
}
};
($name:ident, $type_:expr, $nr:expr, $ty:ty) => {
$crate::ioctl_writeread!(
$name,
$crate::sys::ioctl::ioctl_iowr::<$ty>($type_, $nr),
$ty
);
};
($name:ident, $code:expr) => {
#[allow(clippy::missing_safety_doc)]
pub unsafe fn $name<F: ::std::os::fd::AsFd, T>(
fd: &F,
val: &mut T,
) -> ::std::io::Result<libc::c_int> {
let op = $code;
$crate::ffi!(unsafe {
::libc::ioctl(
::std::os::fd::AsRawFd::as_raw_fd(&fd.as_fd()),
op as _,
val as *mut T,
)
})
}
};
}
#[macro_export]
macro_rules! ioctl_writeread_buf {
($name:ident, $code:expr, $ty:ident) => {
#[allow(clippy::missing_safety_doc)]
pub unsafe fn $name<F: ::std::os::fd::AsFd, const N: usize>(
fd: &F,
val: &mut $ty<N>,
) -> ::std::io::Result<libc::c_int> {
let op = $code;
$crate::ffi!(unsafe {
::libc::ioctl(
::std::os::fd::AsRawFd::as_raw_fd(&fd.as_fd()),
op as _,
val as *mut $ty<N>,
)
})
}
};
($name:ident, $type_:expr, $nr:expr, $ty:ident) => {
$crate::ioctl_writeread_buf!(
$name,
$crate::sys::ioctl::ioctl_iowr::<$ty<0>>($type_, $nr),
$ty
);
};
}
#[macro_export]
macro_rules! ioctl_read {
($name:ident, $code:expr, $ty:ty) => {
#[allow(clippy::missing_safety_doc)]
pub unsafe fn $name<F: ::std::os::fd::AsFd>(fd: &F) -> ::std::io::Result<$ty> {
let mut val = ::core::mem::MaybeUninit::<$ty>::uninit();
let op = $code;
$crate::ffi!(unsafe {
::libc::ioctl(
::std::os::fd::AsRawFd::as_raw_fd(&fd.as_fd()),
op as _,
val.as_mut_ptr(),
)
})?;
::std::io::Result::Ok(unsafe { val.assume_init() })
}
};
($name:ident, $type_:expr, $nr:expr, $ty:ty) => {
$crate::ioctl_read!(
$name,
$crate::sys::ioctl::ioctl_ior::<$ty>($type_, $nr),
$ty
);
};
}
#[cfg(test)]
#[path = "ioctl_test.rs"]
mod tests;