Skip to main content

virtio_media/
protocol.rs

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
5use enumn::N;
6use v4l2r::bindings::v4l2_event;
7use v4l2r::ioctl::V4l2Buffer;
8use zerocopy::FromBytes;
9use zerocopy::Immutable;
10use zerocopy::IntoBytes;
11
12pub const VIRTIO_ID_MEDIA: u32 = 48;
13
14const VIRTIO_MEDIA_CARD_NAME_LEN: usize = 32;
15#[derive(Debug, Immutable, IntoBytes)]
16#[repr(C)]
17pub 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
26impl AsRef<[u8]> for VirtioMediaDeviceConfig {
27    fn as_ref(&self) -> &[u8] {
28        self.as_bytes()
29    }
30}
31
32pub const VIRTIO_MEDIA_CMD_OPEN: u32 = 1;
33pub const VIRTIO_MEDIA_CMD_CLOSE: u32 = 2;
34pub const VIRTIO_MEDIA_CMD_IOCTL: u32 = 3;
35pub const VIRTIO_MEDIA_CMD_MMAP: u32 = 4;
36pub const VIRTIO_MEDIA_CMD_MUNMAP: u32 = 5;
37
38pub 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)]
43pub 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, FromBytes, Immutable)]
130pub struct SgEntry {
131    pub start: u64,
132    pub len: u32,
133    __padding: u32,
134}
135
136#[repr(C)]
137#[derive(Debug, FromBytes, Immutable)]
138pub struct CmdHeader {
139    pub cmd: u32,
140    _padding: u32,
141}
142
143#[repr(C)]
144#[derive(Debug, Immutable, IntoBytes)]
145pub struct RespHeader {
146    pub errno: i32,
147    _padding: u32,
148}
149
150impl RespHeader {
151    pub fn ok() -> Self {
152        Self {
153            errno: 0,
154            _padding: 0,
155        }
156    }
157
158    pub fn err(errno: i32) -> Self {
159        Self { errno, _padding: 0 }
160    }
161}
162
163#[repr(C)]
164#[derive(Debug, FromBytes, Immutable)]
165pub struct OpenCmd {}
166
167#[repr(C)]
168#[derive(Debug, Immutable, IntoBytes)]
169pub struct OpenResp {
170    hdr: RespHeader,
171    session_id: u32,
172    _padding: u32,
173}
174
175impl OpenResp {
176    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, FromBytes, Immutable)]
187pub struct CloseCmd {
188    pub session_id: u32,
189    _padding: u32,
190}
191
192#[repr(C)]
193#[derive(Debug, FromBytes, Immutable)]
194pub struct IoctlCmd {
195    pub session_id: u32,
196    pub code: u32,
197}
198
199#[repr(C)]
200#[derive(Debug, FromBytes, Immutable)]
201pub struct MmapCmd {
202    pub session_id: u32,
203    pub flags: u32,
204    pub offset: u32,
205}
206
207#[repr(C)]
208#[derive(Debug, Immutable, IntoBytes)]
209pub struct MmapResp {
210    hdr: RespHeader,
211    driver_addr: u64,
212    len: u64,
213}
214
215impl MmapResp {
216    pub fn ok(addr: u64, len: u64) -> Self {
217        Self {
218            hdr: RespHeader::ok(),
219            driver_addr: addr,
220            len,
221        }
222    }
223}
224
225#[repr(C)]
226#[derive(Debug, FromBytes, Immutable)]
227pub struct MunmapCmd {
228    pub driver_addr: u64,
229}
230
231#[repr(C)]
232#[derive(Debug, Immutable, IntoBytes)]
233pub struct MunmapResp {
234    hdr: RespHeader,
235}
236
237impl MunmapResp {
238    pub fn ok() -> Self {
239        Self {
240            hdr: RespHeader::ok(),
241        }
242    }
243}
244
245pub const VIRTIO_MEDIA_EVENT_ERROR: u32 = 0;
246pub const VIRTIO_MEDIA_EVENT_DQBUF: u32 = 1;
247pub const VIRTIO_MEDIA_EVENT_EVENT: u32 = 2;
248
249#[repr(C)]
250#[derive(Debug, Immutable, IntoBytes)]
251pub struct EventHeader {
252    event: u32,
253    session_id: u32,
254}
255
256impl EventHeader {
257    pub fn new(event: u32, session_id: u32) -> Self {
258        Self { event, session_id }
259    }
260}
261
262#[repr(C)]
263#[derive(Debug, Immutable, IntoBytes)]
264pub struct ErrorEvent {
265    hdr: EventHeader,
266    errno: i32,
267    _padding: u32,
268}
269
270impl ErrorEvent {
271    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)]
282pub struct DequeueBufferEvent {
283    hdr: EventHeader,
284    v4l2_buffer: V4l2Buffer,
285}
286
287impl DequeueBufferEvent {
288    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)]
297pub struct SessionEvent {
298    pub hdr: EventHeader,
299    v4l2_event: v4l2_event,
300}
301
302impl SessionEvent {
303    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)]
312pub enum V4l2Event {
313    Error(ErrorEvent),
314    DequeueBuffer(DequeueBufferEvent),
315    Event(SessionEvent),
316}