lesavka/server/src/bin/lesavka_uvc/control_payloads.rs

163 lines
4.1 KiB
Rust

fn send_response(fd: i32, _req: libc::c_ulong, _payload: &[u8]) -> Result<()> {
let _ = fd;
anyhow::bail!("coverage harness does not send ioctl responses")
}
#[cfg(coverage)]
fn send_stall(fd: i32, _req: libc::c_ulong) -> Result<()> {
let _ = fd;
anyhow::bail!("coverage harness does not send stall ioctls")
}
#[cfg(coverage)]
fn build_streaming_control(cfg: &UvcConfig, ctrl_len: usize) -> [u8; STREAM_CTRL_SIZE_MAX] {
let mut buf = [0u8; STREAM_CTRL_SIZE_MAX];
write_le16(&mut buf[0..2], 1);
buf[2] = 1;
buf[3] = uvc_frame_index_for_mode(cfg.width, cfg.height);
write_le32(&mut buf[4..8], cfg.interval);
write_le16(&mut buf[8..10], 0);
write_le16(&mut buf[10..12], 0);
write_le16(&mut buf[12..14], 0);
write_le16(&mut buf[14..16], 0);
write_le16(&mut buf[16..18], 0);
write_le32(&mut buf[18..22], cfg.frame_size);
write_le32(&mut buf[22..26], cfg.max_packet);
if ctrl_len >= STREAM_CTRL_SIZE_15 {
write_le32(&mut buf[26..30], 48_000_000);
buf[30] = 0x03;
buf[31] = 0x01;
buf[32] = 0x01;
buf[33] = 0x01;
}
buf
}
fn uvc_frame_index_for_mode(width: u32, height: u32) -> u8 {
match (width, height) {
(1920, 1080) => 1,
(1280, 720) => 2,
_ => 2,
}
}
fn uvc_frame_index_for_request(requested: u8, cfg: &UvcConfig) -> u8 {
match requested {
1 | 2 => requested,
_ => uvc_frame_index_for_mode(cfg.width, cfg.height),
}
}
fn uvc_frame_size_for_index(frame_index: u8, fallback: u32) -> u32 {
match frame_index {
1 | 2 => fallback,
_ => fallback,
}
}
#[cfg(coverage)]
fn parse_ctrl_request(data: [u8; 64]) -> UsbCtrlRequest {
UsbCtrlRequest {
b_request_type: data[0],
b_request: data[1],
w_value: u16::from_le_bytes([data[2], data[3]]),
w_index: u16::from_le_bytes([data[4], data[5]]),
w_length: u16::from_le_bytes([data[6], data[7]]),
}
}
#[cfg(coverage)]
fn parse_request_data(data: [u8; 64]) -> UvcRequestData {
let length = i32::from_le_bytes([data[0], data[1], data[2], data[3]]);
let mut out = [0u8; UVC_DATA_SIZE];
out.copy_from_slice(&data[4..64]);
UvcRequestData { length, data: out }
}
#[cfg(coverage)]
fn stream_ctrl_len() -> usize {
let value = env_u32("LESAVKA_UVC_CTRL_LEN", STREAM_CTRL_SIZE_15 as u32) as usize;
match value {
STREAM_CTRL_SIZE_11 | STREAM_CTRL_SIZE_15 => value,
_ => STREAM_CTRL_SIZE_11,
}
}
#[cfg(coverage)]
fn env_u32(name: &str, default: u32) -> u32 {
env::var(name)
.ok()
.and_then(|v| v.parse::<u32>().ok())
.unwrap_or(default)
}
#[cfg(coverage)]
fn env_u8(name: &str) -> Option<u8> {
env::var(name).ok().and_then(|v| v.parse::<u8>().ok())
}
#[cfg(coverage)]
fn env_u32_opt(name: &str) -> Option<u32> {
env::var(name).ok().and_then(|v| v.parse::<u32>().ok())
}
#[cfg(coverage)]
fn read_u32_file(path: &str) -> Option<u32> {
std::fs::read_to_string(path)
.ok()
.and_then(|v| v.trim().parse::<u32>().ok())
}
#[cfg(coverage)]
fn read_u32_first(path: &str) -> Option<u32> {
std::fs::read_to_string(path)
.ok()
.and_then(|v| v.split_whitespace().next()?.parse::<u32>().ok())
}
#[cfg(coverage)]
fn read_configfs_snapshot() -> Option<ConfigfsSnapshot> {
None
}
#[cfg(coverage)]
fn log_configfs_snapshot(state: &mut UvcState, _label: &str) {
let _ = state;
}
#[cfg(coverage)]
fn adjust_length(mut bytes: Vec<u8>, w_length: u16) -> Vec<u8> {
let want = (w_length as usize).min(UVC_DATA_SIZE);
bytes.resize(want, 0);
bytes.truncate(want);
bytes
}
#[cfg(coverage)]
fn write_le16(dst: &mut [u8], val: u16) {
let bytes = val.to_le_bytes();
dst[0] = bytes[0];
dst[1] = bytes[1];
}
#[cfg(coverage)]
fn write_le32(dst: &mut [u8], val: u32) {
let bytes = val.to_le_bytes();
dst[0] = bytes[0];
dst[1] = bytes[1];
dst[2] = bytes[2];
dst[3] = bytes[3];
}
#[cfg(coverage)]
fn read_le32(src: &[u8], offset: usize) -> u32 {
u32::from_le_bytes([
src[offset],
src[offset + 1],
src[offset + 2],
src[offset + 3],
])
}