libv4l-rs
libv4l-rs copied to clipboard
Device serial and model info
I need to tell the difference between devices using their media device info. I wrote the following, but it'd be great to see something similar in the library:
use std::{
ffi::{c_char, CStr},
os::fd::AsRawFd,
path::Path,
};
use nix::ioctl_readwrite;
/// A struct that contains information about some Linux media device.
///
/// See: https://docs.kernel.org/userspace-api/media/mediactl/media-ioc-device-info.html
#[repr(C)]
pub(super) struct MediaDeviceInfo {
driver: [c_char; 16],
model: [c_char; 32],
serial: [c_char; 40],
bus_info: [c_char; 32],
media_version: u32,
hw_revision: u32,
driver_version: u32,
reserved: [u32; 31],
}
const MEDIA_IOC_DEVICE_INFO: u8 = 0x00;
const IOCTL_MEDIA_COMMAND: u8 = b'|';
// call `media_ioc_device_info` to execute the `ioctl`
ioctl_readwrite!(
media_ioc_device_info,
IOCTL_MEDIA_COMMAND,
MEDIA_IOC_DEVICE_INFO,
MediaDeviceInfo
);
impl MediaDeviceInfo {
/// Attempts to get information about the media device at the given path.
pub fn get(path: &Path) -> Result<Self, std::io::Error> {
// create an uninitialized MediaDeviceInfo
//
// SAFETY: This is fine since the kernel will write to this zeroed memory.
let mut info = unsafe { std::mem::zeroed::<MediaDeviceInfo>() };
// grab the file descriptor
let file = std::fs::File::open(path)?;
let fd = file.as_raw_fd();
// perform the ioctl
//
// SAFETY: The kernel will either write to this or fail to do so.
//
// If it does fail, we return using the question mark operator.
unsafe {
media_ioc_device_info(fd, &mut info)?;
}
Ok(info)
}
pub fn model(&self) -> String {
unsafe {
CStr::from_ptr(self.model.as_ptr())
.to_str()
.unwrap_or_else(|_| {
tracing::error!("`ioctl` to get capture device model contained invalid UTF-8");
"Model was not valid UTF-8"
})
.to_string()
}
}
pub fn serial(&self) -> String {
unsafe {
CStr::from_ptr(self.serial.as_ptr())
.to_str()
.unwrap_or_else(|_| {
tracing::error!("`ioctl` to get capture device serial contained invalid UTF-8");
"Serial was not valid UTF-8"
})
.to_string()
}
}
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use super::*;
#[test]
fn test_media_device_info() {
let info = MediaDeviceInfo::get(&PathBuf::from("/dev/media0")).unwrap();
assert_eq!(String::from("C922 Pro Stream Webcam"), info.model());
}
}
https://docs.kernel.org/userspace-api/media/mediactl/media-ioc-device-info.html#c.MC.MEDIA_IOC_DEVICE_INFO