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::().ok()) .unwrap_or(default) } #[cfg(coverage)] fn env_u8(name: &str) -> Option { env::var(name).ok().and_then(|v| v.parse::().ok()) } #[cfg(coverage)] fn env_u32_opt(name: &str) -> Option { env::var(name).ok().and_then(|v| v.parse::().ok()) } #[cfg(coverage)] fn read_u32_file(path: &str) -> Option { std::fs::read_to_string(path) .ok() .and_then(|v| v.trim().parse::().ok()) } #[cfg(coverage)] fn read_u32_first(path: &str) -> Option { std::fs::read_to_string(path) .ok() .and_then(|v| v.split_whitespace().next()?.parse::().ok()) } #[cfg(coverage)] fn read_configfs_snapshot() -> Option { None } #[cfg(coverage)] fn log_configfs_snapshot(state: &mut UvcState, _label: &str) { let _ = state; } #[cfg(coverage)] fn adjust_length(mut bytes: Vec, w_length: u16) -> Vec { 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], ]) }