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

Rust 如何使用ioctl+;nix宏以获取可变大小的缓冲区,rust,usb,ioctl,usb-hid,Rust,Usb,Ioctl,Usb Hid,这是一个相关的问题,但不是同一个问题 我想检索一个可变大小的缓冲区。还有另一个ioctl告诉我需要读取X字节。C标题也告诉我以下内容: #定义HID_MAX_描述符_大小4096 #定义HIDIOCGRDESC IOR('H',0x02,结构hidraw报告描述符) 结构hidraw报告描述符{ __u32尺寸; __u8值[隐藏最大描述符大小]; }; 我用以下方式定义宏: ioctl_read_buf!(hid_read_descr, b'H', 0x02, u8); 稍后致电: let

这是一个相关的问题,但不是同一个问题

我想检索一个可变大小的缓冲区。还有另一个
ioctl
告诉我需要读取X字节。C标题也告诉我以下内容:

#定义HID_MAX_描述符_大小4096
#定义HIDIOCGRDESC IOR('H',0x02,结构hidraw报告描述符)
结构hidraw报告描述符{
__u32尺寸;
__u8值[隐藏最大描述符大小];
};
我用以下方式定义宏:

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初始化
desc_raw
,在调用之后,它似乎没有被触动


我是否错误地使用了
ioctl\u read\u buf
宏?

我认为这里有几个问题。有些在生锈的一侧,有些则错误地使用了
HIDIOCGRDESC
ioctl。如果查看Linux内核发行版中的hidraw.txt和hid example.c代码,结构的使用如下所示:

struct hidraw\u report\u descriptor rpt\u desc;
memset(&rpt_desc,0x0,sizeof(rpt_desc));
/*获取报告描述符*/
rpt_desc.size=desc_size;
res=ioctl(fd、HIDIOCGRDESC和rpt_desc);
desc_size
来自上一个
HIDIOCGRDESCSIZE
ioctl调用。除非填写正确的大小参数,否则ioctl将返回错误(
ENOTTY
EINVAL

在不使用
libc::open
的情况下,传递
O_NONBLOCK
标志以打开HID设备也存在问题。我的结局是:

#[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);
        }
    }
}
最后,您不应该将结构的大小调整为可变大小,ioctl头表示存在一个固定的最大值。可变性完全由系统ioctl来处理,它只需要来自另一个ioctl调用的预期大小提示

既然

我是否错误地使用了
ioctl\u read\u buf

我认为在这里使用它是不正确的。您不希望读取数据数组,而是希望读取特定类型的单个实例。这就是你读到的用于

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

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

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(())
}
使用libc;//0.2.66
使用nix::ioctl_read;//0.16.1
使用std::{
fs::OpenOptions,
mem::可能是因为,
os::unix::{fs::OpenOptionText,io::AsRawFd},
};
常量HID_最大描述符_大小:usize=4096;
#[报告员(C)]
发布结构hidraw\u报告\u描述符{
尺寸:u32,
值:[u8;隐藏\u最大\u描述符\u大小],
}
瞧!(hid_read_sz,b'H',0x01,libc::c_int);
瞧!(隐藏读取描述,b'H',0x02,隐藏报告描述符);
fn main()->结果{
让file=OpenOptions::new()
.读(真)
.写(真)
.custom_标志(libc::O_非块)
.open(“/dev/hidraw0”)?;
不安全{
设fd=file.as_raw_fd();
设mut size=0;
hid_read_sz(fd和mut大小)?;
println!(“{}”,大小);
让mut desc_raw=maybeunit:::uninit();
(*desc_raw.as_mut_ptr()).size=尺寸为u32;
hid_read_descr(file.as_raw_fd(),desc_raw.as_mut_ptr())?;
让desc_raw=desc_raw。假设_init();
让数据=&desc_raw.value[…desc_raw.size as usize];
println!(“{:02x?}”,数据);
}
好(())
}

请查看如何创建一个,然后查看您的问题以将其包括在内。我们无法说出代码中存在哪些板条箱、类型、特征、字段等。试着制造一些能再现你在网络上的错误的东西,或者你可以在一个全新的货运项目中再现它。还有。什么是
外部板条箱ffi
?使用
i32
for
hid\u read\u sz
并不像它应该的那样便携,可能会触发未定义的行为。C的
int
大小因平台而异。这是我今天早些时候想知道的<代码>libc::c_int非常酷。从我的版本中进行了很好的清理!我肯定至少学到了一两件事。