代码之家  ›  专栏  ›  技术社区  ›  Juan Leni

如何使用ioctl+nix宏获取可变大小的缓冲区

  •  2
  • Juan Leni  · 技术社区  · 6 年前

    How to use nix's ioctl? 但这不是同一个问题。

    我想检索一个可变大小的缓冲区。还有一个 ioctl

    #define HID_MAX_DESCRIPTOR_SIZE     4096
    #define HIDIOCGRDESC        _IOR('H', 0x02, struct hidraw_report_descriptor)
    
    struct hidraw_report_descriptor {
        __u32 size;
        __u8 value[HID_MAX_DESCRIPTOR_SIZE];
    };
    

    我按以下方式定义宏:

    ioctl_read_buf!(hid_read_descr, b'H', 0x02, u8);
    

    稍后打电话给:

    let mut desc_raw = [0u8; 4 + 4096];
    let err = unsafe { hid_read_descr(file.as_raw_fd(), &mut desc_raw); };
    

    做这个的时候, desc_raw 满是零。我本以为前4个字节包含 size 基于结构定义。

    另一种方法,似乎也行不通

    ioctl_read!(hid_read_descr2, b'H', 0x02, [u8; 4+4096]);
    // ...
    let mut desc_raw = [0xFFu8; 4 + 4096];
    let err = unsafe { hid_read_descr2(file.as_raw_fd(), &mut desc_raw); };
    

    在这两种情况下,我都试图初始化 使用0xFF并在调用之后,它似乎没有受到影响。

    ioctl_read_buf 宏错误?

    2 回复  |  直到 6 年前
        1
  •  4
  •   Shepmaster Tim Diekmann    5 年前

    既然 Digikata has thoughtfully provided enough code to drive the program ...

    ioctl_read_buf 宏错误?

    我可以这么说 这里不正确。不想读取数据数组,只想读取特定类型的单个实例。那就是 ioctl_read! 是为了。

    repr(C) 模仿C定义的结构。这确保了诸如对齐、填充、字段排序等重要细节都与我们调用的代码一一匹配。

    然后,我们可以构造此结构的未初始化实例,并将其传递给新定义的函数。

    use libc; // 0.2.66
    use nix::ioctl_read; // 0.16.1
    use std::{
        fs::OpenOptions,
        mem::MaybeUninit,
        os::unix::{fs::OpenOptionsExt, io::AsRawFd},
    };
    
    const HID_MAX_DESCRIPTOR_SIZE: usize = 4096;
    
    #[repr(C)]
    pub struct hidraw_report_descriptor {
        size: u32,
        value: [u8; HID_MAX_DESCRIPTOR_SIZE],
    }
    
    ioctl_read!(hid_read_sz, b'H', 0x01, libc::c_int);
    ioctl_read!(hid_read_descr, b'H', 0x02, hidraw_report_descriptor);
    
    fn main() -> Result<(), Box<dyn std::error::Error>> {
        let file = OpenOptions::new()
            .read(true)
            .write(true)
            .custom_flags(libc::O_NONBLOCK)
            .open("/dev/hidraw0")?;
    
        unsafe {
            let fd = file.as_raw_fd();
    
            let mut size = 0;
            hid_read_sz(fd, &mut size)?;
            println!("{}", size);
    
            let mut desc_raw = MaybeUninit::<hidraw_report_descriptor>::uninit();
            (*desc_raw.as_mut_ptr()).size = size as u32;
            hid_read_descr(file.as_raw_fd(), desc_raw.as_mut_ptr())?;
            let desc_raw = desc_raw.assume_init();
            let data = &desc_raw.value[..desc_raw.size as usize];
            println!("{:02x?}", data);
        }
    
        Ok(())
    }
    
        2
  •  2
  •   Digikata    6 年前

    我想你有几个问题。有些在生锈的一面,有些在使用 HIDIOCGRDESC

    struct hidraw_report_descriptor rpt_desc;
    
    memset(&rpt_desc, 0x0, sizeof(rpt_desc));
    
    /* Get Report Descriptor */
    rpt_desc.size = desc_size;
    res = ioctl(fd, HIDIOCGRDESC, &rpt_desc);
    

    desc_size HIDIOCGRDESCSIZE ioctl呼叫。除非填写正确的大小参数,否则ioctl将返回一个错误( ENOTTY EINVAL ).

    O_NONBLOCK 在不使用的情况下打开HID设备的标志 libc::open . 我的结局是:

    #[macro_use]
    extern crate nix;
    
    extern crate libc;
    
    ioctl_read!(hid_read_sz, b'H', 0x01, i32);
    ioctl_read_buf!(hid_read_descr, b'H', 0x02, u8);
    
    fn main() {
        // see /usr/include/linux/hidraw.h
        // and hid-example.c
        extern crate ffi;
        use std::ffi::CString;
        let fname = CString::new("/dev/hidraw0").unwrap();
        let fd = unsafe { libc::open(fname.as_ptr(), libc::O_NONBLOCK | libc::O_RDWR) };
    
        let mut sz = 0i32;
        let err = unsafe { hid_read_sz(fd, &mut sz) };
        println!("{:?} size is {:?}", err, sz);
    
        let mut desc_raw = [0x0u8; 4 + 4096];
    
        // sz on my system ended up as 52 - this handjams in the value
        // w/ a little endian swizzle into the C struct .size field, but
        // really we should properly define the struct
        desc_raw[0] = sz as u8;
    
        let err = unsafe { hid_read_descr(fd, &mut desc_raw) };
        println!("{:?}", err);
    
        for (i, &b) in desc_raw.iter().enumerate() {
            if b != 0 {
                println!("{:4} {:?}", i, b);
            }
        }
    }