Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Device serial and model info #109

Open
onkoe opened this issue Sep 1, 2024 · 2 comments
Open

Device serial and model info #109

onkoe opened this issue Sep 1, 2024 · 2 comments

Comments

@onkoe
Copy link
Contributor

onkoe commented Sep 1, 2024

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

@MarijnS95
Copy link
Collaborator

@onkoe I've implemented most of the mediactl API 2.5 years ago at https://github.com/marijns95/libv4l-rs/compare/media, would you mind checking that out and seeing if it works for you?

I'll rebase it, button it up and see if I can create a PR out of it.

@onkoe
Copy link
Contributor Author

onkoe commented Sep 3, 2024

It appears that this branch would work great! Thanks for your effort!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants