use enumn::N;
use v4l2r::bindings::v4l2_event;
use v4l2r::ioctl::V4l2Buffer;
use zerocopy::FromBytes;
use zerocopy::Immutable;
use zerocopy::IntoBytes;
pub const VIRTIO_ID_MEDIA: u32 = 48;
const VIRTIO_MEDIA_CARD_NAME_LEN: usize = 32;
#[derive(Debug, Immutable, IntoBytes)]
#[repr(C)]
pub struct VirtioMediaDeviceConfig {
pub device_caps: u32,
pub device_type: u32,
pub card: [u8; VIRTIO_MEDIA_CARD_NAME_LEN],
}
impl AsRef<[u8]> for VirtioMediaDeviceConfig {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
pub const VIRTIO_MEDIA_CMD_OPEN: u32 = 1;
pub const VIRTIO_MEDIA_CMD_CLOSE: u32 = 2;
pub const VIRTIO_MEDIA_CMD_IOCTL: u32 = 3;
pub const VIRTIO_MEDIA_CMD_MMAP: u32 = 4;
pub const VIRTIO_MEDIA_CMD_MUNMAP: u32 = 5;
pub const VIRTIO_MEDIA_MMAP_FLAG_RW: u32 = 1 << 0;
#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
#[repr(u32)]
#[allow(non_camel_case_types)]
pub enum V4l2Ioctl {
VIDIOC_QUERYCAP = 0,
VIDIOC_ENUM_FMT = 2,
VIDIOC_G_FMT = 4,
VIDIOC_S_FMT = 5,
VIDIOC_REQBUFS = 8,
VIDIOC_QUERYBUF = 9,
VIDIOC_G_FBUF = 10,
VIDIOC_S_FBUF = 11,
VIDIOC_OVERLAY = 14,
VIDIOC_QBUF = 15,
VIDIOC_EXPBUF = 16,
VIDIOC_DQBUF = 17,
VIDIOC_STREAMON = 18,
VIDIOC_STREAMOFF = 19,
VIDIOC_G_PARM = 21,
VIDIOC_S_PARM = 22,
VIDIOC_G_STD = 23,
VIDIOC_S_STD = 24,
VIDIOC_ENUMSTD = 25,
VIDIOC_ENUMINPUT = 26,
VIDIOC_G_CTRL = 27,
VIDIOC_S_CTRL = 28,
VIDIOC_G_TUNER = 29,
VIDIOC_S_TUNER = 30,
VIDIOC_G_AUDIO = 33,
VIDIOC_S_AUDIO = 34,
VIDIOC_QUERYCTRL = 36,
VIDIOC_QUERYMENU = 37,
VIDIOC_G_INPUT = 38,
VIDIOC_S_INPUT = 39,
VIDIOC_G_EDID = 40,
VIDIOC_S_EDID = 41,
VIDIOC_G_OUTPUT = 46,
VIDIOC_S_OUTPUT = 47,
VIDIOC_ENUMOUTPUT = 48,
VIDIOC_G_AUDOUT = 49,
VIDIOC_S_AUDOUT = 50,
VIDIOC_G_MODULATOR = 54,
VIDIOC_S_MODULATOR = 55,
VIDIOC_G_FREQUENCY = 56,
VIDIOC_S_FREQUENCY = 57,
VIDIOC_CROPCAP = 58,
VIDIOC_G_CROP = 59,
VIDIOC_S_CROP = 60,
VIDIOC_G_JPEGCOMP = 61,
VIDIOC_S_JPEGCOMP = 62,
VIDIOC_QUERYSTD = 63,
VIDIOC_TRY_FMT = 64,
VIDIOC_ENUMAUDIO = 65,
VIDIOC_ENUMAUDOUT = 66,
VIDIOC_G_PRIORITY = 67,
VIDIOC_S_PRIORITY = 68,
VIDIOC_G_SLICED_VBI_CAP = 69,
VIDIOC_LOG_STATUS = 70,
VIDIOC_G_EXT_CTRLS = 71,
VIDIOC_S_EXT_CTRLS = 72,
VIDIOC_TRY_EXT_CTRLS = 73,
VIDIOC_ENUM_FRAMESIZES = 74,
VIDIOC_ENUM_FRAMEINTERVALS = 75,
VIDIOC_G_ENC_INDEX = 76,
VIDIOC_ENCODER_CMD = 77,
VIDIOC_TRY_ENCODER_CMD = 78,
VIDIOC_DBG_S_REGISTER = 79,
VIDIOC_DBG_G_REGISTER = 80,
VIDIOC_S_HW_FREQ_SEEK = 82,
VIDIOC_S_DV_TIMINGS = 87,
VIDIOC_G_DV_TIMINGS = 88,
VIDIOC_DQEVENT = 89,
VIDIOC_SUBSCRIBE_EVENT = 90,
VIDIOC_UNSUBSCRIBE_EVENT = 91,
VIDIOC_CREATE_BUFS = 92,
VIDIOC_PREPARE_BUF = 93,
VIDIOC_G_SELECTION = 94,
VIDIOC_S_SELECTION = 95,
VIDIOC_DECODER_CMD = 96,
VIDIOC_TRY_DECODER_CMD = 97,
VIDIOC_ENUM_DV_TIMINGS = 98,
VIDIOC_QUERY_DV_TIMINGS = 99,
VIDIOC_DV_TIMINGS_CAP = 100,
VIDIOC_ENUM_FREQ_BANDS = 101,
VIDIOC_DBG_G_CHIP_INFO = 102,
VIDIOC_QUERY_EXT_CTRL = 103,
}
#[repr(C)]
#[derive(Debug, FromBytes, Immutable)]
pub struct SgEntry {
pub start: u64,
pub len: u32,
__padding: u32,
}
#[repr(C)]
#[derive(Debug, FromBytes, Immutable)]
pub struct CmdHeader {
pub cmd: u32,
_padding: u32,
}
#[repr(C)]
#[derive(Debug, Immutable, IntoBytes)]
pub struct RespHeader {
pub errno: i32,
_padding: u32,
}
impl RespHeader {
pub fn ok() -> Self {
Self {
errno: 0,
_padding: 0,
}
}
pub fn err(errno: i32) -> Self {
Self { errno, _padding: 0 }
}
}
#[repr(C)]
#[derive(Debug, FromBytes, Immutable)]
pub struct OpenCmd {}
#[repr(C)]
#[derive(Debug, Immutable, IntoBytes)]
pub struct OpenResp {
hdr: RespHeader,
session_id: u32,
_padding: u32,
}
impl OpenResp {
pub fn ok(session_id: u32) -> Self {
Self {
hdr: RespHeader::ok(),
session_id,
_padding: 0,
}
}
}
#[repr(C)]
#[derive(Debug, FromBytes, Immutable)]
pub struct CloseCmd {
pub session_id: u32,
_padding: u32,
}
#[repr(C)]
#[derive(Debug, FromBytes, Immutable)]
pub struct IoctlCmd {
pub session_id: u32,
pub code: u32,
}
#[repr(C)]
#[derive(Debug, FromBytes, Immutable)]
pub struct MmapCmd {
pub session_id: u32,
pub flags: u32,
pub offset: u32,
}
#[repr(C)]
#[derive(Debug, Immutable, IntoBytes)]
pub struct MmapResp {
hdr: RespHeader,
driver_addr: u64,
len: u64,
}
impl MmapResp {
pub fn ok(addr: u64, len: u64) -> Self {
Self {
hdr: RespHeader::ok(),
driver_addr: addr,
len,
}
}
}
#[repr(C)]
#[derive(Debug, FromBytes, Immutable)]
pub struct MunmapCmd {
pub driver_addr: u64,
}
#[repr(C)]
#[derive(Debug, Immutable, IntoBytes)]
pub struct MunmapResp {
hdr: RespHeader,
}
impl MunmapResp {
pub fn ok() -> Self {
Self {
hdr: RespHeader::ok(),
}
}
}
pub const VIRTIO_MEDIA_EVENT_ERROR: u32 = 0;
pub const VIRTIO_MEDIA_EVENT_DQBUF: u32 = 1;
pub const VIRTIO_MEDIA_EVENT_EVENT: u32 = 2;
#[repr(C)]
#[derive(Debug, Immutable, IntoBytes)]
pub struct EventHeader {
event: u32,
session_id: u32,
}
impl EventHeader {
pub fn new(event: u32, session_id: u32) -> Self {
Self { event, session_id }
}
}
#[repr(C)]
#[derive(Debug, Immutable, IntoBytes)]
pub struct ErrorEvent {
hdr: EventHeader,
errno: i32,
_padding: u32,
}
impl ErrorEvent {
pub fn new(session_id: u32, errno: i32) -> Self {
Self {
hdr: EventHeader::new(VIRTIO_MEDIA_EVENT_ERROR, session_id),
errno,
_padding: 0,
}
}
}
#[repr(C)]
#[derive(Debug)]
pub struct DequeueBufferEvent {
hdr: EventHeader,
v4l2_buffer: V4l2Buffer,
}
impl DequeueBufferEvent {
pub fn new(session_id: u32, v4l2_buffer: V4l2Buffer) -> Self {
Self {
hdr: EventHeader::new(VIRTIO_MEDIA_EVENT_DQBUF, session_id),
v4l2_buffer,
}
}
}
#[repr(C)]
pub struct SessionEvent {
pub hdr: EventHeader,
v4l2_event: v4l2_event,
}
impl SessionEvent {
pub fn new(session_id: u32, v4l2_event: v4l2_event) -> Self {
Self {
hdr: EventHeader::new(VIRTIO_MEDIA_EVENT_EVENT, session_id),
v4l2_event,
}
}
}
#[allow(clippy::large_enum_variant)]
pub enum V4l2Event {
Error(ErrorEvent),
DequeueBuffer(DequeueBufferEvent),
Event(SessionEvent),
}