nix
nix copied to clipboard
Can't use ioctl with media_device_info, result is always ENOTTY
I have lost some time already trying to figure out how to use ioctl with nix, but until now I couldn't get it work. Is there any documentation with examples that could help ? From what I read this could is correct and should work.
use nix;
use std::os::unix::io::AsRawFd;
// https://www.kernel.org/doc/html/latest/userspace-api/media/mediactl/media-ioc-device-info.html#description
#[repr(C)]
pub struct MediaDeviceInfo {
driver_name: [char; 16], // ASCII
device_name: [char; 32], // UTF-8
serial_number: [char; 40], // ASCII
bus_info: [char; 32], // ASCII
media_version: u32, // Media API version, formatted with the KERNEL_VERSION() macro.
hardware_device_version: u32, // Hardware device revision in a driver-specific format.
driver_version: u32, // Media device driver version, formatted with the KERNEL_VERSION() macro. Together with the driver field this identifies a particular driver.
reserved: [u32; 31], // Reserved for future extensions. Drivers and applications must set this array to zero.
}
// https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/media.h#L372
nix::ioctl_readwrite!(media_ioc_device_info, b'|', 0x00, MediaDeviceInfo);
fn main() {
let video_device = std::fs::File::open("/dev/video0").unwrap();
let video_device_pointer = video_device.as_raw_fd();
let mut media_device_info: MediaDeviceInfo = unsafe { std::mem::zeroed() };
let result = unsafe { media_ioc_device_info(video_device_pointer, &mut media_device_info) };
println!("device_name: {:#?}", media_device_info.device_name);
println!("result: {:#?}", result);
}
Have you looked at the tests in Nix's test/sys/test_ioctl.rs directory?
ENOTTY usually indicates that you either got the ioctl number wrong, or you're trying to use it on the wrong kind of file descriptor. If you run your program with strace, it will attempt to decode the ioctl number. If you see MEDIA_IOC_DEVICE_INFO in strace's output then you know you defined it correctly.
I don't know if is related but when implement usbapi crate I noticed that I could now use standard macros in nix and implemented ioctl_readwrite_ptr and ioctl_read_ptr. Full code here https://gitlab.com/mike7b4/usbapi-rs/-/blob/master/src/os/linux/usbfs.rs
snippets:
#[macro_export]
macro_rules! ioctl_read_ptr {
($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
$(#[$attr])*
/// # Safety
/// ioctl call need unsafe calls to C
pub unsafe fn $name(fd: nix::libc::c_int,
data: *const $ty)
-> nix::Result<nix::libc::c_int> {
convert_ioctl_res!(nix::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as nix::sys::ioctl::ioctl_num_type, data))
}
)
}
#[macro_export]
macro_rules! ioctl_readwrite_ptr {
($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
$(#[$attr])*
/// # Safety
/// ioctl call need unsafe calls to C
pub unsafe fn $name(fd: nix::libc::c_int,
data: *mut $ty)
-> nix::Result<nix::libc::c_int> {
convert_ioctl_res!(nix::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as nix::sys::ioctl::ioctl_num_type, data))
}
)
}
You're opening the wrong device. Try /dev/media0.
As a side note, you shouldbe using std::ffi::c_char rather than char. The latter is a Unicode code point.
@patrickelectric did you continue working on the code? Media interface would be useful to have.
I'm going to close the issue, on the assumption that the OP figured his problem out.