如何使用 ioctl + nix 宏获取可变大小的缓冲区
How to use ioctl + nix macros to get a variable size buffer
这与 有关,但不是同一个问题。
我想检索可变大小的缓冲区。还有另一个 ioctl
告诉我需要读取 X 个字节。 C header 也告诉我以下内容:
#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 初始化 desc_raw
并且在调用之后,它似乎没有受到影响。
我是否错误地使用了 ioctl_read_buf
宏?
我认为您遇到了一些问题。一些在 Rust 方面,一些在不正确地使用 HIDIOCGRDESC
ioctl 的情况下。如果你在 hidraw.txt 和 hid-example.c 代码中查看 Linux 内核分布,结构的使用如下:
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 returns 会出错(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 header 表示预期有一个固定的最大值。可变性全部由系统 ioctl 处理,它只需要来自另一个 ioctl 调用的预期大小提示。
现在 ...
Am I using the ioctl_read_buf
macro incorrectly?
我会说在这里使用它是不正确的。您不想读取数据数组,而是想读取特定类型的单个实例。这就是 ioctl_read!
的目的。
我们定义了一个模仿 C 定义的 repr(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(())
}
这与
我想检索可变大小的缓冲区。还有另一个 ioctl
告诉我需要读取 X 个字节。 C header 也告诉我以下内容:
#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 初始化 desc_raw
并且在调用之后,它似乎没有受到影响。
我是否错误地使用了 ioctl_read_buf
宏?
我认为您遇到了一些问题。一些在 Rust 方面,一些在不正确地使用 HIDIOCGRDESC
ioctl 的情况下。如果你在 hidraw.txt 和 hid-example.c 代码中查看 Linux 内核分布,结构的使用如下:
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 returns 会出错(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 header 表示预期有一个固定的最大值。可变性全部由系统 ioctl 处理,它只需要来自另一个 ioctl 调用的预期大小提示。
现在
Am I using the
ioctl_read_buf
macro incorrectly?
我会说在这里使用它是不正确的。您不想读取数据数组,而是想读取特定类型的单个实例。这就是 ioctl_read!
的目的。
我们定义了一个模仿 C 定义的 repr(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(())
}