1 // Copyright 2024 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use enumn::N; 6 use v4l2r::bindings::v4l2_event; 7 use v4l2r::ioctl::V4l2Buffer; 8 use zerocopy::AsBytes; 9 use zerocopy::FromBytes; 10 use zerocopy::FromZeroes; 11 12 pub const VIRTIO_ID_MEDIA: u32 = 49; 13 14 const VIRTIO_MEDIA_CARD_NAME_LEN: usize = 32; 15 #[derive(Debug, AsBytes)] 16 #[repr(C)] 17 pub struct VirtioMediaDeviceConfig { 18 /// The device_caps field of struct video_device. 19 pub device_caps: u32, 20 /// The vfl_devnode_type of the device. 21 pub device_type: u32, 22 /// The `card` field of v4l2_capability. 23 pub card: [u8; VIRTIO_MEDIA_CARD_NAME_LEN], 24 } 25 26 impl AsRef<[u8]> for VirtioMediaDeviceConfig { as_ref(&self) -> &[u8]27 fn as_ref(&self) -> &[u8] { 28 self.as_bytes() 29 } 30 } 31 32 pub const VIRTIO_MEDIA_CMD_OPEN: u32 = 1; 33 pub const VIRTIO_MEDIA_CMD_CLOSE: u32 = 2; 34 pub const VIRTIO_MEDIA_CMD_IOCTL: u32 = 3; 35 pub const VIRTIO_MEDIA_CMD_MMAP: u32 = 4; 36 pub const VIRTIO_MEDIA_CMD_MUNMAP: u32 = 5; 37 38 pub const VIRTIO_MEDIA_MMAP_FLAG_RW: u32 = 1 << 0; 39 40 #[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)] 41 #[repr(u32)] 42 #[allow(non_camel_case_types)] 43 pub enum V4l2Ioctl { 44 VIDIOC_QUERYCAP = 0, 45 VIDIOC_ENUM_FMT = 2, 46 VIDIOC_G_FMT = 4, 47 VIDIOC_S_FMT = 5, 48 VIDIOC_REQBUFS = 8, 49 VIDIOC_QUERYBUF = 9, 50 VIDIOC_G_FBUF = 10, 51 VIDIOC_S_FBUF = 11, 52 VIDIOC_OVERLAY = 14, 53 VIDIOC_QBUF = 15, 54 VIDIOC_EXPBUF = 16, 55 VIDIOC_DQBUF = 17, 56 VIDIOC_STREAMON = 18, 57 VIDIOC_STREAMOFF = 19, 58 VIDIOC_G_PARM = 21, 59 VIDIOC_S_PARM = 22, 60 VIDIOC_G_STD = 23, 61 VIDIOC_S_STD = 24, 62 VIDIOC_ENUMSTD = 25, 63 VIDIOC_ENUMINPUT = 26, 64 VIDIOC_G_CTRL = 27, 65 VIDIOC_S_CTRL = 28, 66 VIDIOC_G_TUNER = 29, 67 VIDIOC_S_TUNER = 30, 68 VIDIOC_G_AUDIO = 33, 69 VIDIOC_S_AUDIO = 34, 70 VIDIOC_QUERYCTRL = 36, 71 VIDIOC_QUERYMENU = 37, 72 VIDIOC_G_INPUT = 38, 73 VIDIOC_S_INPUT = 39, 74 VIDIOC_G_EDID = 40, 75 VIDIOC_S_EDID = 41, 76 VIDIOC_G_OUTPUT = 46, 77 VIDIOC_S_OUTPUT = 47, 78 VIDIOC_ENUMOUTPUT = 48, 79 VIDIOC_G_AUDOUT = 49, 80 VIDIOC_S_AUDOUT = 50, 81 VIDIOC_G_MODULATOR = 54, 82 VIDIOC_S_MODULATOR = 55, 83 VIDIOC_G_FREQUENCY = 56, 84 VIDIOC_S_FREQUENCY = 57, 85 VIDIOC_CROPCAP = 58, 86 VIDIOC_G_CROP = 59, 87 VIDIOC_S_CROP = 60, 88 VIDIOC_G_JPEGCOMP = 61, 89 VIDIOC_S_JPEGCOMP = 62, 90 VIDIOC_QUERYSTD = 63, 91 VIDIOC_TRY_FMT = 64, 92 VIDIOC_ENUMAUDIO = 65, 93 VIDIOC_ENUMAUDOUT = 66, 94 VIDIOC_G_PRIORITY = 67, 95 VIDIOC_S_PRIORITY = 68, 96 VIDIOC_G_SLICED_VBI_CAP = 69, 97 VIDIOC_LOG_STATUS = 70, 98 VIDIOC_G_EXT_CTRLS = 71, 99 VIDIOC_S_EXT_CTRLS = 72, 100 VIDIOC_TRY_EXT_CTRLS = 73, 101 VIDIOC_ENUM_FRAMESIZES = 74, 102 VIDIOC_ENUM_FRAMEINTERVALS = 75, 103 VIDIOC_G_ENC_INDEX = 76, 104 VIDIOC_ENCODER_CMD = 77, 105 VIDIOC_TRY_ENCODER_CMD = 78, 106 VIDIOC_DBG_S_REGISTER = 79, 107 VIDIOC_DBG_G_REGISTER = 80, 108 VIDIOC_S_HW_FREQ_SEEK = 82, 109 VIDIOC_S_DV_TIMINGS = 87, 110 VIDIOC_G_DV_TIMINGS = 88, 111 VIDIOC_DQEVENT = 89, 112 VIDIOC_SUBSCRIBE_EVENT = 90, 113 VIDIOC_UNSUBSCRIBE_EVENT = 91, 114 VIDIOC_CREATE_BUFS = 92, 115 VIDIOC_PREPARE_BUF = 93, 116 VIDIOC_G_SELECTION = 94, 117 VIDIOC_S_SELECTION = 95, 118 VIDIOC_DECODER_CMD = 96, 119 VIDIOC_TRY_DECODER_CMD = 97, 120 VIDIOC_ENUM_DV_TIMINGS = 98, 121 VIDIOC_QUERY_DV_TIMINGS = 99, 122 VIDIOC_DV_TIMINGS_CAP = 100, 123 VIDIOC_ENUM_FREQ_BANDS = 101, 124 VIDIOC_DBG_G_CHIP_INFO = 102, 125 VIDIOC_QUERY_EXT_CTRL = 103, 126 } 127 128 #[repr(C)] 129 #[derive(Debug, FromZeroes, FromBytes)] 130 pub struct SgEntry { 131 pub start: u64, 132 pub len: u32, 133 __padding: u32, 134 } 135 136 #[repr(C)] 137 #[derive(Debug, FromZeroes, FromBytes)] 138 pub struct CmdHeader { 139 pub cmd: u32, 140 _padding: u32, 141 } 142 143 #[repr(C)] 144 #[derive(Debug, AsBytes)] 145 pub struct RespHeader { 146 pub errno: i32, 147 _padding: u32, 148 } 149 150 impl RespHeader { ok() -> Self151 pub fn ok() -> Self { 152 Self { 153 errno: 0, 154 _padding: 0, 155 } 156 } 157 err(errno: i32) -> Self158 pub fn err(errno: i32) -> Self { 159 Self { errno, _padding: 0 } 160 } 161 } 162 163 #[repr(C)] 164 #[derive(Debug, FromZeroes, FromBytes)] 165 pub struct OpenCmd {} 166 167 #[repr(C)] 168 #[derive(Debug, AsBytes)] 169 pub struct OpenResp { 170 hdr: RespHeader, 171 session_id: u32, 172 _padding: u32, 173 } 174 175 impl OpenResp { ok(session_id: u32) -> Self176 pub fn ok(session_id: u32) -> Self { 177 Self { 178 hdr: RespHeader::ok(), 179 session_id, 180 _padding: 0, 181 } 182 } 183 } 184 185 #[repr(C)] 186 #[derive(Debug, FromZeroes, FromBytes)] 187 pub struct CloseCmd { 188 pub session_id: u32, 189 _padding: u32, 190 } 191 192 #[repr(C)] 193 #[derive(Debug, FromZeroes, FromBytes)] 194 pub struct IoctlCmd { 195 pub session_id: u32, 196 pub code: u32, 197 } 198 199 #[repr(C)] 200 #[derive(Debug, FromZeroes, FromBytes)] 201 pub struct MmapCmd { 202 pub session_id: u32, 203 pub flags: u32, 204 pub offset: u32, 205 } 206 207 #[repr(C)] 208 #[derive(Debug, AsBytes)] 209 pub struct MmapResp { 210 hdr: RespHeader, 211 guest_addr: u64, 212 len: u64, 213 } 214 215 impl MmapResp { ok(addr: u64, len: u64) -> Self216 pub fn ok(addr: u64, len: u64) -> Self { 217 Self { 218 hdr: RespHeader::ok(), 219 guest_addr: addr, 220 len, 221 } 222 } 223 } 224 225 #[repr(C)] 226 #[derive(Debug, FromZeroes, FromBytes)] 227 pub struct MunmapCmd { 228 pub guest_addr: u64, 229 } 230 231 #[repr(C)] 232 #[derive(Debug, AsBytes)] 233 pub struct MunmapResp { 234 hdr: RespHeader, 235 } 236 237 impl MunmapResp { ok() -> Self238 pub fn ok() -> Self { 239 Self { 240 hdr: RespHeader::ok(), 241 } 242 } 243 } 244 245 pub const VIRTIO_MEDIA_EVENT_ERROR: u32 = 0; 246 pub const VIRTIO_MEDIA_EVENT_DQBUF: u32 = 1; 247 pub const VIRTIO_MEDIA_EVENT_EVENT: u32 = 2; 248 249 #[repr(C)] 250 #[derive(Debug, AsBytes)] 251 pub struct EventHeader { 252 event: u32, 253 session_id: u32, 254 } 255 256 impl EventHeader { new(event: u32, session_id: u32) -> Self257 pub fn new(event: u32, session_id: u32) -> Self { 258 Self { event, session_id } 259 } 260 } 261 262 #[repr(C)] 263 #[derive(Debug, AsBytes)] 264 pub struct ErrorEvent { 265 hdr: EventHeader, 266 errno: i32, 267 _padding: u32, 268 } 269 270 impl ErrorEvent { new(session_id: u32, errno: i32) -> Self271 pub fn new(session_id: u32, errno: i32) -> Self { 272 Self { 273 hdr: EventHeader::new(VIRTIO_MEDIA_EVENT_ERROR, session_id), 274 errno, 275 _padding: 0, 276 } 277 } 278 } 279 280 #[repr(C)] 281 #[derive(Debug)] 282 pub struct DequeueBufferEvent { 283 hdr: EventHeader, 284 v4l2_buffer: V4l2Buffer, 285 } 286 287 impl DequeueBufferEvent { new(session_id: u32, v4l2_buffer: V4l2Buffer) -> Self288 pub fn new(session_id: u32, v4l2_buffer: V4l2Buffer) -> Self { 289 Self { 290 hdr: EventHeader::new(VIRTIO_MEDIA_EVENT_DQBUF, session_id), 291 v4l2_buffer, 292 } 293 } 294 } 295 296 #[repr(C)] 297 pub struct SessionEvent { 298 pub hdr: EventHeader, 299 v4l2_event: v4l2_event, 300 } 301 302 impl SessionEvent { new(session_id: u32, v4l2_event: v4l2_event) -> Self303 pub fn new(session_id: u32, v4l2_event: v4l2_event) -> Self { 304 Self { 305 hdr: EventHeader::new(VIRTIO_MEDIA_EVENT_EVENT, session_id), 306 v4l2_event, 307 } 308 } 309 } 310 311 #[allow(clippy::large_enum_variant)] 312 pub enum V4l2Event { 313 Error(ErrorEvent), 314 DequeueBuffer(DequeueBufferEvent), 315 Event(SessionEvent), 316 } 317