1use 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 pub device_caps: u32,
20 pub device_type: u32,
22 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}