use data_model::Le16;
use data_model::Le32;
use data_model::Le64;
use serde::Deserialize;
use serde::Serialize;
use zerocopy::FromBytes;
use zerocopy::Immutable;
use zerocopy::IntoBytes;
use zerocopy::KnownLayout;
pub const VIRTIO_DEVICE_TYPE_SPECIFIC_FEATURES_MASK: u64 = 0xfffc_0000_00ff_ffff;
pub mod block {
    use super::*;
    pub const VIRTIO_BLK_T_IN: u32 = 0;
    pub const VIRTIO_BLK_T_OUT: u32 = 1;
    pub const VIRTIO_BLK_T_FLUSH: u32 = 4;
    pub const VIRTIO_BLK_T_GET_ID: u32 = 8;
    pub const VIRTIO_BLK_T_DISCARD: u32 = 11;
    pub const VIRTIO_BLK_T_WRITE_ZEROES: u32 = 13;
    pub const VIRTIO_BLK_S_OK: u8 = 0;
    pub const VIRTIO_BLK_S_IOERR: u8 = 1;
    pub const VIRTIO_BLK_S_UNSUPP: u8 = 2;
    pub const VIRTIO_BLK_F_SEG_MAX: u32 = 2;
    pub const VIRTIO_BLK_F_RO: u32 = 5;
    pub const VIRTIO_BLK_F_BLK_SIZE: u32 = 6;
    pub const VIRTIO_BLK_F_FLUSH: u32 = 9;
    pub const VIRTIO_BLK_F_MQ: u32 = 12;
    pub const VIRTIO_BLK_F_DISCARD: u32 = 13;
    pub const VIRTIO_BLK_F_WRITE_ZEROES: u32 = 14;
    #[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
    #[repr(C)]
    pub struct virtio_blk_geometry {
        cylinders: Le16,
        heads: u8,
        sectors: u8,
    }
    #[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
    #[repr(C)]
    pub struct virtio_blk_topology {
        physical_block_exp: u8,
        alignment_offset: u8,
        min_io_size: Le16,
        opt_io_size: Le32,
    }
    #[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
    #[repr(C, packed)]
    pub struct virtio_blk_config {
        pub capacity: Le64,
        pub size_max: Le32,
        pub seg_max: Le32,
        pub geometry: virtio_blk_geometry,
        pub blk_size: Le32,
        pub topology: virtio_blk_topology,
        pub writeback: u8,
        pub unused0: u8,
        pub num_queues: Le16,
        pub max_discard_sectors: Le32,
        pub max_discard_seg: Le32,
        pub discard_sector_alignment: Le32,
        pub max_write_zeroes_sectors: Le32,
        pub max_write_zeroes_seg: Le32,
        pub write_zeroes_may_unmap: u8,
        pub unused1: [u8; 3],
    }
    #[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
    #[repr(C)]
    pub(crate) struct virtio_blk_req_header {
        pub req_type: Le32,
        pub reserved: Le32,
        pub sector: Le64,
    }
    #[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
    #[repr(C)]
    pub(crate) struct virtio_blk_discard_write_zeroes {
        pub sector: Le64,
        pub num_sectors: Le32,
        pub flags: Le32,
    }
    pub(crate) const VIRTIO_BLK_DISCARD_WRITE_ZEROES_FLAG_UNMAP: u32 = 1 << 0;
}
pub mod fs {
    pub const FS_MAX_TAG_LEN: usize = 36;
}
pub mod gpu {
    use super::*;
    pub const NUM_QUEUES: usize = 2;
    pub const VIRTIO_GPU_F_VIRGL: u32 = 0;
    pub const VIRTIO_GPU_F_EDID: u32 = 1;
    pub const VIRTIO_GPU_F_RESOURCE_UUID: u32 = 2;
    pub const VIRTIO_GPU_F_RESOURCE_BLOB: u32 = 3;
    pub const VIRTIO_GPU_F_CONTEXT_INIT: u32 = 4;
    pub const VIRTIO_GPU_F_FENCE_PASSING: u32 = 5;
    pub const VIRTIO_GPU_F_CREATE_GUEST_HANDLE: u32 = 6;
    pub const VIRTIO_GPU_SHM_ID_HOST_VISIBLE: u8 = 0x0001;
    #[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
    #[repr(C)]
    pub struct virtio_gpu_config {
        pub events_read: Le32,
        pub events_clear: Le32,
        pub num_scanouts: Le32,
        pub num_capsets: Le32,
    }
}
pub mod snd {
    use super::*;
    #[derive(
        Copy,
        Clone,
        Default,
        FromBytes,
        Immutable,
        IntoBytes,
        KnownLayout,
        Serialize,
        Deserialize,
        PartialEq,
        Eq,
        Debug,
    )]
    #[repr(C, packed)]
    pub struct virtio_snd_config {
        pub jacks: Le32,
        pub streams: Le32,
        pub chmaps: Le32,
    }
}
pub mod media {
    const QUEUE_SIZE: u16 = 256;
    pub const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE, QUEUE_SIZE];
}
pub mod video {
    use data_model::Le32;
    use serde::Deserialize;
    use serde::Serialize;
    use serde_keyvalue::FromKeyValues;
    use zerocopy::FromBytes;
    use zerocopy::Immutable;
    use zerocopy::IntoBytes;
    use zerocopy::KnownLayout;
    pub const CMD_QUEUE_INDEX: usize = 0;
    pub const EVENT_QUEUE_INDEX: usize = 1;
    pub const NUM_QUEUES: usize = 2;
    pub const VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES: u32 = 0;
    pub const VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG: u32 = 1;
    pub const VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT: u32 = 2;
    #[derive(Debug, Clone, Copy)]
    pub enum VideoDeviceType {
        Decoder,
        Encoder,
    }
    #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)]
    #[serde(rename_all = "kebab-case")]
    pub enum VideoBackendType {
        #[cfg(feature = "libvda")]
        Libvda,
        #[cfg(feature = "libvda")]
        LibvdaVd,
        #[cfg(feature = "ffmpeg")]
        Ffmpeg,
        #[cfg(feature = "vaapi")]
        Vaapi,
    }
    #[derive(Debug, Serialize, Deserialize, FromKeyValues)]
    pub struct VideoDeviceConfig {
        pub backend: VideoBackendType,
    }
    pub fn ffmpeg_supported_virtio_features() -> u64 {
        1u64 << VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES
            | 1u64 << VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG
            | 1u64 << VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT
    }
    pub fn vaapi_supported_virtio_features() -> u64 {
        1u64 << VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES
            | 1u64 << VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG
            | 1u64 << VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT
    }
    pub fn vda_supported_virtio_features() -> u64 {
        1u64 << VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG | 1u64 << VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT
    }
    pub fn backend_supported_virtio_features(backend: VideoBackendType) -> u64 {
        match backend {
            #[cfg(feature = "libvda")]
            VideoBackendType::Libvda | VideoBackendType::LibvdaVd => {
                vda_supported_virtio_features()
            }
            #[cfg(feature = "ffmpeg")]
            VideoBackendType::Ffmpeg => ffmpeg_supported_virtio_features(),
            #[cfg(feature = "vaapi")]
            VideoBackendType::Vaapi => vaapi_supported_virtio_features(),
        }
    }
    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
    pub struct virtio_video_config {
        pub version: Le32,
        pub max_caps_length: Le32,
        pub max_resp_length: Le32,
        pub device_name: [u8; 32],
    }
}
pub mod vsock {
    pub const NUM_QUEUES: usize = 3;
}
pub mod wl {
    pub const NUM_QUEUES: usize = 2;
    pub const VIRTIO_WL_F_TRANS_FLAGS: u32 = 0x01;
    pub const VIRTIO_WL_F_SEND_FENCES: u32 = 0x02;
    pub const VIRTIO_WL_F_USE_SHMEM: u32 = 0x03;
}
pub mod console {
    use data_model::Le16;
    use data_model::Le32;
    use zerocopy::FromBytes;
    use zerocopy::Immutable;
    use zerocopy::IntoBytes;
    use zerocopy::KnownLayout;
    pub const VIRTIO_CONSOLE_F_SIZE: u32 = 0;
    pub const VIRTIO_CONSOLE_F_MULTIPORT: u32 = 1;
    pub const VIRTIO_CONSOLE_F_EMERG_WRITE: u32 = 2;
    #[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
    #[repr(C)]
    pub struct virtio_console_config {
        pub cols: Le16,
        pub rows: Le16,
        pub max_nr_ports: Le32,
        pub emerg_wr: Le32,
    }
    #[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
    #[repr(C)]
    pub struct virtio_console_control {
        pub id: Le32,
        pub event: Le16,
        pub value: Le16,
    }
    #[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
    #[repr(C)]
    pub struct virtio_console_resize {
        pub cols: Le16,
        pub rows: Le16,
    }
    pub const VIRTIO_CONSOLE_DEVICE_READY: u16 = 0;
    pub const VIRTIO_CONSOLE_DEVICE_ADD: u16 = 1;
    pub const VIRTIO_CONSOLE_DEVICE_REMOVE: u16 = 2;
    pub const VIRTIO_CONSOLE_PORT_READY: u16 = 3;
    pub const VIRTIO_CONSOLE_CONSOLE_PORT: u16 = 4;
    pub const VIRTIO_CONSOLE_RESIZE: u16 = 5;
    pub const VIRTIO_CONSOLE_PORT_OPEN: u16 = 6;
    pub const VIRTIO_CONSOLE_PORT_NAME: u16 = 7;
}