xref: /aosp_15_r20/external/virtio-media/device/src/protocol.rs (revision 1b4853f54772485c5dd4001ae33a7a958bcc97a1)
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