linux_video_core/impls/
controls.rs

1use crate::{calls, types::*, Internal, Result};
2use core::mem::{ManuallyDrop, MaybeUninit};
3use std::os::unix::io::RawFd;
4
5/// Control value
6pub struct Value<C: AsRef<QueryExtCtrl>> {
7    ctrl: C,
8    data: Internal<ExtControl>,
9}
10
11impl<C: AsRef<QueryExtCtrl>> From<C> for Value<C> {
12    fn from(ctrl: C) -> Self {
13        let data = Internal::<ExtControl>::new(ctrl.as_ref());
14
15        Self { ctrl, data }
16    }
17}
18
19impl<C: AsRef<QueryExtCtrl>> core::ops::Deref for Value<C> {
20    type Target = C;
21    fn deref(&self) -> &Self::Target {
22        &self.ctrl
23    }
24}
25
26impl<C: AsRef<QueryExtCtrl>> Value<C> {
27    pub fn control(&self) -> &C {
28        &self.ctrl
29    }
30
31    pub fn try_ref<T: RefValue<ExtControl>>(&self) -> Option<&T> {
32        T::try_ref(&self.data, self.ctrl.as_ref())
33    }
34
35    pub fn try_mut<T: MutValue<ExtControl>>(&mut self) -> Option<&mut T> {
36        T::try_mut(&mut self.data, self.ctrl.as_ref())
37    }
38}
39
40impl<C: AsRef<QueryExtCtrl>> Drop for Value<C> {
41    fn drop(&mut self) {
42        if self.ctrl.as_ref().has_payload() {
43            self.data.del();
44        }
45    }
46}
47
48impl AsRef<QueryExtCtrl> for QueryExtCtrl {
49    fn as_ref(&self) -> &Self {
50        self
51    }
52}
53
54impl<C: AsRef<QueryExtCtrl>> GetValue for Value<C> {
55    /// Get value from device
56    fn get(&mut self, fd: RawFd) -> Result<()> {
57        let ctrls = MaybeUninit::<ExtControls>::zeroed();
58
59        unsafe_call!({
60            let mut ctrls = ctrls.assume_init();
61
62            ctrls.count = 1;
63            ctrls.controls = self.data.as_mut() as *mut _;
64
65            calls::g_ext_ctrls(fd, &mut ctrls as *mut _)
66        })?;
67
68        Ok(())
69    }
70}
71
72impl<C: AsRef<QueryExtCtrl>> SetValue for Value<C> {
73    /// Set value to device
74    fn set(&self, fd: RawFd) -> Result<()> {
75        let req = MaybeUninit::<ExtControls>::zeroed();
76
77        unsafe_call!({
78            let mut req = req.assume_init();
79
80            req.count = 1;
81            req.controls = self.data.as_ref() as *const _ as *mut _;
82
83            calls::s_ext_ctrls(fd, &mut req as *mut _)
84        })?;
85
86        Ok(())
87    }
88}
89
90impl Internal<ExtControl> {
91    pub fn new(ctrl: &QueryExtCtrl) -> Self {
92        let data = MaybeUninit::<ExtControl>::zeroed();
93        let size = ctrl.size();
94
95        let ptr = if ctrl.has_payload() {
96            let mut data = Vec::<u8>::with_capacity(size as _);
97            let ptr = data.as_mut_ptr();
98            let _ = ManuallyDrop::new(data);
99            ptr
100        } else {
101            core::ptr::null_mut()
102        };
103
104        let data = unsafe {
105            let mut data = data.assume_init();
106
107            data.union_.ptr = ptr as _;
108
109            data.id = ctrl.id;
110            data.size = size;
111
112            data
113        };
114
115        Self(data)
116    }
117
118    pub fn del(&mut self) {
119        unsafe {
120            let _ = Vec::from_raw_parts(self.union_.ptr as *mut u8, 0, self.size as _);
121            //self.union_.ptr = core::ptr::null_mut();
122        }
123    }
124}
125
126impl RefValue<ExtControl> for str {
127    fn try_ref<'a>(data: &'a ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a Self> {
128        if matches!(ctrl.type_, CtrlType::String) && ctrl.has_payload() {
129            unsafe { core::ffi::CStr::from_ptr(data.union_.string as _) }
130                .to_str()
131                .ok()
132        } else {
133            None
134        }
135    }
136}
137
138/// Plain control value types
139pub trait IsPlainCtrlData {
140    /// Control types
141    const TYPES: &'static [CtrlType];
142}
143
144macro_rules! value_impl {
145    ($($type:ty: $($ctrl_type:ident)*,)*) => {
146        $(
147            impl IsPlainCtrlData for $type {
148                const TYPES: &'static [CtrlType] = &[ $(CtrlType::$ctrl_type,)* ];
149            }
150        )*
151    };
152}
153
154value_impl! {
155    i32: Integer,
156    bool: Boolean,
157    i64: Integer64,
158    CtrlClass: CtrlClass,
159    u8: U8 BitMask Menu IntegerMenu,
160    u16: U16 BitMask Menu IntegerMenu,
161    u32: U32 BitMask Menu IntegerMenu,
162    Area: Area,
163    Hdr10CllInfo: Hdr10CllInfo,
164    Hdr10MasteringDisplay: Hdr10MasteringDisplay,
165    H264Sps: H264Sps,
166    H264Pps: H264Pps,
167    H264ScalingMatrix: H264ScalingMatrix,
168    H264SliceParams: H264SliceParams,
169    H264DecodeParams: H264DecodeParams,
170    H264PredWeights: H264PredWeights,
171    FwhtParams: FwhtParams,
172    //Vp8Params: Vp8Params,
173    Mpeg2Quantisation: Mpeg2Quantisation,
174    Mpeg2Sequence: Mpeg2Sequence,
175    Mpeg2Picture: Mpeg2Picture,
176    Vp9CompressedHdr: Vp9CompressedHdr,
177    Vp9Frame: Vp9Frame,
178}
179
180pub trait RefValue<T> {
181    /// Get reference to value
182    fn try_ref<'a>(data: &'a T, ctrl: &QueryExtCtrl) -> Option<&'a Self>;
183}
184
185pub trait MutValue<T> {
186    /// Get mutable reference to value
187    fn try_mut<'a>(data: &'a mut T, ctrl: &QueryExtCtrl) -> Option<&'a mut Self>;
188}
189
190pub trait GetValue {
191    /// Get value from device
192    fn get(&mut self, fd: RawFd) -> Result<()>;
193}
194
195pub trait SetValue {
196    /// Set value to device
197    fn set(&self, fd: RawFd) -> Result<()>;
198}
199
200impl<T: IsPlainCtrlData> RefValue<ExtControl> for T {
201    fn try_ref<'a>(data: &'a ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a Self> {
202        if T::TYPES.contains(&ctrl.type_) {
203            if ctrl.has_payload() {
204                if core::mem::size_of::<T>() as u32 <= data.size {
205                    return Some(unsafe { &*(data.union_.ptr as *const _) });
206                }
207            } else if core::mem::size_of::<T>() <= core::mem::size_of::<ExtControlUnion>() {
208                return Some(unsafe { &*(&data.union_.value as *const _ as *const _) });
209            }
210        }
211        None
212    }
213}
214
215impl<T: IsPlainCtrlData> MutValue<ExtControl> for T {
216    fn try_mut<'a>(data: &'a mut ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a mut Self> {
217        if T::TYPES.contains(&ctrl.type_) {
218            if ctrl.has_payload() {
219                if core::mem::size_of::<T>() as u32 <= data.size {
220                    return Some(unsafe { &mut *(data.union_.ptr as *mut _) });
221                }
222            } else if core::mem::size_of::<T>() <= core::mem::size_of::<ExtControlUnion>() {
223                return Some(unsafe { &mut *(&mut data.union_.value as *mut _ as *mut _) });
224            }
225        }
226        None
227    }
228}
229
230impl<const N: usize, T: IsPlainCtrlData> RefValue<ExtControl> for [T; N] {
231    fn try_ref<'a>(data: &'a ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a Self> {
232        if T::TYPES.contains(&ctrl.type_)
233            && ctrl.has_payload()
234            && core::mem::size_of::<Self>() as u32 <= data.size
235        {
236            Some(unsafe { &*(data.union_.ptr as *const _) })
237        } else {
238            None
239        }
240    }
241}
242
243impl<const N: usize, T: IsPlainCtrlData> MutValue<ExtControl> for [T; N] {
244    fn try_mut<'a>(data: &'a mut ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a mut Self> {
245        if T::TYPES.contains(&ctrl.type_)
246            && ctrl.has_payload()
247            && core::mem::size_of::<Self>() as u32 <= data.size
248        {
249            Some(unsafe { &mut *(data.union_.ptr as *mut _) })
250        } else {
251            None
252        }
253    }
254}
255
256impl<const N: usize, const M: usize, T: IsPlainCtrlData> RefValue<ExtControl> for [[T; N]; M] {
257    fn try_ref<'a>(data: &'a ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a Self> {
258        if T::TYPES.contains(&ctrl.type_)
259            && ctrl.has_payload()
260            && core::mem::size_of::<Self>() as u32 <= data.size
261        {
262            Some(unsafe { &*(data.union_.ptr as *const _) })
263        } else {
264            None
265        }
266    }
267}
268
269impl<const N: usize, const M: usize, T: IsPlainCtrlData> MutValue<ExtControl> for [[T; N]; M] {
270    fn try_mut<'a>(data: &'a mut ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a mut Self> {
271        if T::TYPES.contains(&ctrl.type_)
272            && ctrl.has_payload()
273            && core::mem::size_of::<Self>() as u32 <= data.size
274        {
275            Some(unsafe { &mut *(data.union_.ptr as *mut _) })
276        } else {
277            None
278        }
279    }
280}
281
282impl<const N: usize, const M: usize, const L: usize, T: IsPlainCtrlData> RefValue<ExtControl>
283    for [[[T; N]; M]; L]
284{
285    fn try_ref<'a>(data: &'a ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a Self> {
286        if T::TYPES.contains(&ctrl.type_)
287            && ctrl.has_payload()
288            && core::mem::size_of::<Self>() as u32 <= data.size
289        {
290            Some(unsafe { &*(data.union_.ptr as *const _) })
291        } else {
292            None
293        }
294    }
295}
296
297impl<const N: usize, const M: usize, const L: usize, T: IsPlainCtrlData> MutValue<ExtControl>
298    for [[[T; N]; M]; L]
299{
300    fn try_mut<'a>(data: &'a mut ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a mut Self> {
301        if T::TYPES.contains(&ctrl.type_)
302            && ctrl.has_payload()
303            && core::mem::size_of::<Self>() as u32 <= data.size
304        {
305            Some(unsafe { &mut *(data.union_.ptr as *mut _) })
306        } else {
307            None
308        }
309    }
310}
311
312impl<const N: usize, const M: usize, const L: usize, const O: usize, T: IsPlainCtrlData>
313    RefValue<ExtControl> for [[[[T; N]; M]; L]; O]
314{
315    fn try_ref<'a>(data: &'a ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a Self> {
316        if T::TYPES.contains(&ctrl.type_)
317            && ctrl.has_payload()
318            && core::mem::size_of::<Self>() as u32 <= data.size
319        {
320            Some(unsafe { &*(data.union_.ptr as *const _) })
321        } else {
322            None
323        }
324    }
325}
326
327impl<const N: usize, const M: usize, const L: usize, const O: usize, T: IsPlainCtrlData>
328    MutValue<ExtControl> for [[[[T; N]; M]; L]; O]
329{
330    fn try_mut<'a>(data: &'a mut ExtControl, ctrl: &QueryExtCtrl) -> Option<&'a mut Self> {
331        if T::TYPES.contains(&ctrl.type_)
332            && ctrl.has_payload()
333            && core::mem::size_of::<Self>() as u32 <= data.size
334        {
335            Some(unsafe { &mut *(data.union_.ptr as *mut _) })
336        } else {
337            None
338        }
339    }
340}
341
342/// Control values
343pub struct Values<C: AsRef<QueryExtCtrl>> {
344    ctrls: Vec<C>,
345    datas: Vec<Internal<ExtControl>>,
346}
347
348impl<C: AsRef<QueryExtCtrl>> FromIterator<C> for Values<C> {
349    fn from_iter<T: IntoIterator<Item = C>>(iter: T) -> Self {
350        let mut ctrls = Vec::new();
351        let mut datas = Vec::new();
352
353        for ctrl in iter {
354            datas.push(Internal::<ExtControl>::new(ctrl.as_ref()));
355            ctrls.push(ctrl);
356        }
357
358        Self { ctrls, datas }
359    }
360}
361
362impl<C: AsRef<QueryExtCtrl>> Drop for Values<C> {
363    fn drop(&mut self) {
364        for index in 0..self.len() {
365            let ctrl = &self.ctrls[index];
366            let data = &mut self.datas[index];
367            if ctrl.as_ref().has_payload() {
368                Internal::from(data).del();
369            }
370        }
371    }
372}
373
374impl<C: AsRef<QueryExtCtrl>> Values<C> {
375    /// Number of values
376    pub fn len(&self) -> usize {
377        self.ctrls.len()
378    }
379
380    /// Check for empty
381    pub fn is_empty(&self) -> bool {
382        self.ctrls.is_empty()
383    }
384
385    /// Values controls
386    pub fn controls(&self) -> &[C] {
387        &self.ctrls
388    }
389
390    /// Get reference to value by index
391    pub fn try_ref<T: RefValue<ExtControl>>(&self, index: usize) -> Option<&T> {
392        if index < self.ctrls.len() {
393            T::try_ref(&self.datas[index], self.ctrls[index].as_ref())
394        } else {
395            None
396        }
397    }
398
399    /// Get mutable reference to value by index
400    pub fn try_mut<T: MutValue<ExtControl>>(&mut self, index: usize) -> Option<&mut T> {
401        if index < self.ctrls.len() {
402            T::try_mut(&mut self.datas[index], self.ctrls[index].as_ref())
403        } else {
404            None
405        }
406    }
407}
408
409impl<C: AsRef<QueryExtCtrl>> GetValue for Values<C> {
410    /// Get values from device
411    fn get(&mut self, fd: RawFd) -> Result<()> {
412        let ctrls = MaybeUninit::<ExtControls>::zeroed();
413
414        unsafe_call!({
415            let mut ctrls = ctrls.assume_init();
416
417            ctrls.count = self.ctrls.len() as _;
418            ctrls.controls = self.datas.as_mut_ptr() as _;
419
420            calls::g_ext_ctrls(fd, &mut ctrls).map(|_| ())
421        })
422    }
423}
424
425impl<C: AsRef<QueryExtCtrl>> SetValue for Values<C> {
426    /// Set values to device
427    fn set(&self, fd: RawFd) -> Result<()> {
428        let ctrls = MaybeUninit::<ExtControls>::zeroed();
429
430        unsafe_call!({
431            let mut ctrls = ctrls.assume_init();
432
433            ctrls.count = self.ctrls.len() as _;
434            ctrls.controls = self.datas.as_ptr() as _;
435
436            calls::s_ext_ctrls(fd, &mut ctrls).map(|_| ())
437        })
438    }
439}