firewire_dice_protocols/tcat/extension/
caps_section.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! Capabilities section in protocol extension defined by TCAT for ASICs of DICE.
5//!
6//! The module includes structure, enumeration, and trait and its implementation for capabilities
7//! section in protocol extension defined by TCAT for ASICs of DICE.
8use super::*;
9
10/// Capability of router functionality.
11#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
12pub struct RouterCaps {
13    /// Whether router configuration is exposed to owner software.
14    pub is_exposed: bool,
15    /// Whether router configuration is read only.
16    pub is_readonly: bool,
17    /// Whether router configuration is storable in on-board flash memory.
18    pub is_storable: bool,
19    /// The maximum number of entry for router.
20    pub maximum_entry_count: u16,
21}
22
23impl RouterCaps {
24    const SIZE: usize = 4;
25
26    const IS_EXPOSED_FLAG: u32 = 0x00000001;
27    const IS_READONLY_FLAG: u32 = 0x00000002;
28    const IS_STORABLE_FLAG: u32 = 0x00000004;
29    const MAX_ENTRY_COUNT_MASK: u32 = 0xffff0000;
30    const MAX_ENTYR_COUNT_SHIFT: usize = 16;
31}
32
33#[cfg(test)]
34fn serialize_router_caps(params: &RouterCaps, raw: &mut [u8]) -> Result<(), String> {
35    assert!(raw.len() >= RouterCaps::SIZE);
36
37    let mut val = 0u32;
38
39    if params.is_exposed {
40        val |= RouterCaps::IS_EXPOSED_FLAG;
41    }
42    if params.is_readonly {
43        val |= RouterCaps::IS_READONLY_FLAG;
44    }
45    if params.is_storable {
46        val |= RouterCaps::IS_STORABLE_FLAG;
47    }
48    val |= (params.maximum_entry_count as u32) << RouterCaps::MAX_ENTYR_COUNT_SHIFT;
49
50    serialize_u32(&val, &mut raw[..4]);
51
52    Ok(())
53}
54
55fn deserialize_router_caps(params: &mut RouterCaps, raw: &[u8]) -> Result<(), String> {
56    assert!(raw.len() >= RouterCaps::SIZE);
57
58    let mut val = 0u32;
59    deserialize_u32(&mut val, &raw[..4]);
60
61    params.is_exposed = val & RouterCaps::IS_EXPOSED_FLAG > 0;
62    params.is_readonly = val & RouterCaps::IS_READONLY_FLAG > 0;
63    params.is_storable = val & RouterCaps::IS_STORABLE_FLAG > 0;
64    params.maximum_entry_count =
65        ((val & RouterCaps::MAX_ENTRY_COUNT_MASK) >> RouterCaps::MAX_ENTYR_COUNT_SHIFT) as u16;
66
67    Ok(())
68}
69
70/// Capability of mixer functionality.
71#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
72pub struct MixerCaps {
73    /// Whether mixer configuration is exposed to owner software.
74    pub is_exposed: bool,
75    /// Whether mixer configuration is read only.
76    pub is_readonly: bool,
77    /// Whether mixer configuration is storable in on-board flash memory.
78    pub is_storable: bool,
79    /// The numeric identifier of input device.
80    pub input_device_id: u8,
81    /// The numeric identifier of output device.
82    pub output_device_id: u8,
83    /// The total number of mixer inputs.
84    pub input_count: u8,
85    /// The total number of mixer outputs.
86    pub output_count: u8,
87}
88
89impl MixerCaps {
90    const SIZE: usize = 0x04;
91
92    const IS_EXPOSED_FLAG: u32 = 0x00000001;
93    const IS_READONLY_FLAG: u32 = 0x00000002;
94    const IS_STORABLE_FLAG: u32 = 0x00000004;
95
96    const INPUT_DEVICE_ID_MASK: u32 = 0x000000f0;
97    const OUTPUT_DEVICE_ID_MASK: u32 = 0x00000f00;
98
99    const INPUT_DEVICE_ID_SHIFT: usize = 4;
100    const OUTPUT_DEVICE_ID_SHIFT: usize = 8;
101
102    const INPUT_COUNT_MASK: u32 = 0x00ff0000;
103    const OUTPUT_COUNT_MASK: u32 = 0xff000000;
104
105    const INPUT_COUNT_SHIFT: usize = 16;
106    const OUTPUT_COUNT_SHIFT: usize = 24;
107}
108
109#[cfg(test)]
110fn serialize_mixer_caps(params: &MixerCaps, raw: &mut [u8]) -> Result<(), String> {
111    assert!(raw.len() >= MixerCaps::SIZE);
112
113    let mut val = 0;
114
115    if params.is_exposed {
116        val |= MixerCaps::IS_EXPOSED_FLAG;
117    }
118    if params.is_readonly {
119        val |= MixerCaps::IS_READONLY_FLAG;
120    }
121    if params.is_storable {
122        val |= MixerCaps::IS_STORABLE_FLAG;
123    }
124    val |= (params.input_device_id as u32) << MixerCaps::INPUT_DEVICE_ID_SHIFT;
125    val |= (params.output_device_id as u32) << MixerCaps::OUTPUT_DEVICE_ID_SHIFT;
126    val |= (params.input_count as u32) << 16;
127    val |= (params.output_count as u32) << 24;
128
129    serialize_u32(&val, &mut raw[..4]);
130
131    Ok(())
132}
133
134fn deserialize_mixer_caps(params: &mut MixerCaps, raw: &[u8]) -> Result<(), String> {
135    assert!(raw.len() >= MixerCaps::SIZE);
136
137    let mut val = 0u32;
138    deserialize_u32(&mut val, &raw[..4]);
139
140    params.is_exposed = val & MixerCaps::IS_EXPOSED_FLAG > 0;
141    params.is_readonly = val & MixerCaps::IS_READONLY_FLAG > 0;
142    params.is_storable = val & MixerCaps::IS_STORABLE_FLAG > 0;
143    params.input_device_id =
144        ((val & MixerCaps::INPUT_DEVICE_ID_MASK) >> MixerCaps::INPUT_DEVICE_ID_SHIFT) as u8;
145    params.output_device_id =
146        ((val & MixerCaps::OUTPUT_DEVICE_ID_MASK) >> MixerCaps::OUTPUT_DEVICE_ID_SHIFT) as u8;
147    params.input_count =
148        ((val & MixerCaps::INPUT_COUNT_MASK) >> MixerCaps::INPUT_COUNT_SHIFT) as u8;
149    params.output_count =
150        ((val & MixerCaps::OUTPUT_COUNT_MASK) >> MixerCaps::OUTPUT_COUNT_SHIFT) as u8;
151
152    Ok(())
153}
154
155/// Type of ASIC.
156#[derive(Debug, Copy, Clone, PartialEq, Eq)]
157pub enum AsicType {
158    /// DICE II.
159    DiceII,
160    /// TCD2210 a.k.a DICE Mini.
161    Tcd2210,
162    /// TCD2220 a.k.a DICE Jr.
163    Tcd2220,
164}
165
166impl Default for AsicType {
167    fn default() -> Self {
168        AsicType::DiceII
169    }
170}
171
172/// Capability of general functionality.
173#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
174pub struct GeneralCaps {
175    /// Whether stream format is mutable dynamically.
176    pub dynamic_stream_format: bool,
177    /// Whether on-board flash memory is available.
178    pub storage_avail: bool,
179    /// Whether peak section is available.
180    pub peak_avail: bool,
181    /// The maximum number of tx streams.
182    pub max_tx_streams: u8,
183    /// The maximum number of rx streams.
184    pub max_rx_streams: u8,
185    /// Whether stream format configuration is storable in on-board flash memory.
186    pub stream_format_is_storable: bool,
187    /// The type of ASIC.
188    pub asic_type: AsicType,
189}
190
191impl GeneralCaps {
192    const SIZE: usize = 0x04;
193
194    const DYNAMIC_STREAM_CONF_FLAG: u32 = 0x00000001;
195    const STORAGE_AVAIL_FLAG: u32 = 0x00000002;
196    const PEAK_AVAIL_FLAG: u32 = 0x00000004;
197
198    const MAX_TX_STREAMS_MASK: u32 = 0x000000f0;
199    const MAX_RX_STREAMS_MASK: u32 = 0x00000f00;
200
201    const MAX_TX_STREAMS_SHIFT: usize = 4;
202    const MAX_RX_STREAMS_SHIFT: usize = 8;
203
204    const STREAM_CONF_IS_STORABLE_FLAG: u32 = 0x00001000;
205
206    const DICE_II_VALUE: u16 = 0;
207    const TCD2210_VALUE: u16 = 1;
208    const TCD2220_VALUE: u16 = 2;
209
210    const ASIC_TYPE_MASK: u32 = 0xffff0000;
211    const ASIC_TYPE_SHIFT: usize = 16;
212}
213
214#[cfg(test)]
215fn serialize_general_caps(params: &GeneralCaps, raw: &mut [u8]) -> Result<(), String> {
216    assert!(raw.len() >= GeneralCaps::SIZE);
217
218    let mut val = 0;
219
220    if params.dynamic_stream_format {
221        val |= GeneralCaps::DYNAMIC_STREAM_CONF_FLAG;
222    }
223    if params.storage_avail {
224        val |= GeneralCaps::STORAGE_AVAIL_FLAG;
225    }
226    if params.peak_avail {
227        val |= GeneralCaps::PEAK_AVAIL_FLAG;
228    }
229    val |= (params.max_tx_streams as u32) << GeneralCaps::MAX_TX_STREAMS_SHIFT;
230    val |= (params.max_rx_streams as u32) << GeneralCaps::MAX_RX_STREAMS_SHIFT;
231    if params.stream_format_is_storable {
232        val |= GeneralCaps::STREAM_CONF_IS_STORABLE_FLAG;
233    }
234    let v = match params.asic_type {
235        AsicType::DiceII => GeneralCaps::DICE_II_VALUE,
236        AsicType::Tcd2210 => GeneralCaps::TCD2210_VALUE,
237        AsicType::Tcd2220 => GeneralCaps::TCD2220_VALUE,
238    };
239    val |= (v as u32) << GeneralCaps::ASIC_TYPE_SHIFT;
240
241    serialize_u32(&val, &mut raw[..4]);
242
243    Ok(())
244}
245
246fn deserialize_general_caps(params: &mut GeneralCaps, raw: &[u8]) -> Result<(), String> {
247    assert!(raw.len() >= GeneralCaps::SIZE);
248
249    let mut val = 0u32;
250    deserialize_u32(&mut val, &raw[..4]);
251
252    params.dynamic_stream_format = val & GeneralCaps::DYNAMIC_STREAM_CONF_FLAG > 0;
253    params.storage_avail = val & GeneralCaps::STORAGE_AVAIL_FLAG > 0;
254    params.peak_avail = val & GeneralCaps::PEAK_AVAIL_FLAG > 0;
255    params.max_tx_streams =
256        ((val & GeneralCaps::MAX_TX_STREAMS_MASK) >> GeneralCaps::MAX_TX_STREAMS_SHIFT) as u8;
257    params.max_rx_streams =
258        ((val & GeneralCaps::MAX_RX_STREAMS_MASK) >> GeneralCaps::MAX_RX_STREAMS_SHIFT) as u8;
259    params.stream_format_is_storable = val & GeneralCaps::STREAM_CONF_IS_STORABLE_FLAG > 0;
260    let v = ((val & GeneralCaps::ASIC_TYPE_MASK) >> GeneralCaps::ASIC_TYPE_SHIFT) as u16;
261    params.asic_type = match v {
262        GeneralCaps::DICE_II_VALUE => AsicType::DiceII,
263        GeneralCaps::TCD2210_VALUE => AsicType::Tcd2210,
264        GeneralCaps::TCD2220_VALUE => AsicType::Tcd2220,
265        _ => Err(format!("ASIC type not found for value {}", v))?,
266    };
267
268    Ok(())
269}
270
271/// Capabilities of each funtions.
272#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
273pub struct ExtensionCaps {
274    /// Capabilities for router function.
275    pub router: RouterCaps,
276    /// Capabilities for mixer function.
277    pub mixer: MixerCaps,
278    /// Capabilities for general function.
279    pub general: GeneralCaps,
280}
281
282#[cfg(test)]
283fn serialize_extension_caps(params: &ExtensionCaps, raw: &mut [u8]) -> Result<(), String> {
284    assert!(raw.len() >= ExtensionCaps::SIZE);
285
286    serialize_router_caps(&params.router, &mut raw[..4])?;
287    serialize_mixer_caps(&params.mixer, &mut raw[4..8])?;
288    serialize_general_caps(&params.general, &mut raw[8..12])?;
289
290    Ok(())
291}
292
293pub(crate) fn deserialize_extension_caps(
294    params: &mut ExtensionCaps,
295    raw: &[u8],
296) -> Result<(), String> {
297    assert!(raw.len() >= ExtensionCaps::SIZE);
298
299    deserialize_router_caps(&mut params.router, &raw[..4])?;
300    deserialize_mixer_caps(&mut params.mixer, &raw[4..8])?;
301    deserialize_general_caps(&mut params.general, &raw[8..12])?;
302
303    Ok(())
304}
305
306impl ExtensionCaps {
307    pub(crate) const SIZE: usize = RouterCaps::SIZE + MixerCaps::SIZE + GeneralCaps::SIZE;
308}
309
310/// Operation in capabilities section of TCAT protocol extension.
311pub trait TcatExtensionCapsSectionOperation: TcatExtensionOperation {
312    /// Read capabilities.
313    fn read_extension_caps(
314        req: &FwReq,
315        node: &FwNode,
316        sections: &ExtensionSections,
317        caps: &mut ExtensionCaps,
318        timeout_ms: u32,
319    ) -> Result<(), Error> {
320        let mut raw = vec![0; ExtensionCaps::SIZE];
321        Self::read_extension(req, node, &sections.caps, 0, &mut raw, timeout_ms)
322            .map_err(|e| Error::new(ProtocolExtensionError::Caps, &e.to_string()))?;
323
324        deserialize_extension_caps(caps, &raw)
325            .map_err(|cause| Error::new(ProtocolExtensionError::Caps, &cause))?;
326
327        Ok(())
328    }
329}
330
331impl<O: TcatExtensionOperation> TcatExtensionCapsSectionOperation for O {}
332
333#[cfg(test)]
334mod test {
335    use super::*;
336
337    #[test]
338    fn caps_serdes() {
339        let raw = [
340            0xff, 0x00, 0x00, 0x07, 0x23, 0x12, 0x0c, 0xe7, 0x00, 0x00, 0x1b, 0xa3,
341        ];
342        let caps = ExtensionCaps {
343            router: RouterCaps {
344                is_exposed: true,
345                is_readonly: true,
346                is_storable: true,
347                maximum_entry_count: 0xff00,
348            },
349            mixer: MixerCaps {
350                is_exposed: true,
351                is_readonly: true,
352                is_storable: true,
353                input_device_id: 0x0e,
354                output_device_id: 0x0c,
355                input_count: 0x12,
356                output_count: 0x23,
357            },
358            general: GeneralCaps {
359                dynamic_stream_format: true,
360                storage_avail: true,
361                peak_avail: false,
362                max_tx_streams: 0x0a,
363                max_rx_streams: 0x0b,
364                stream_format_is_storable: true,
365                asic_type: AsicType::DiceII,
366            },
367        };
368        let mut r = vec![0u8; ExtensionCaps::SIZE];
369        serialize_extension_caps(&caps, &mut r).unwrap();
370        assert_eq!(&raw[..], &r);
371
372        let mut c = ExtensionCaps::default();
373        deserialize_extension_caps(&mut c, &raw).unwrap();
374        assert_eq!(caps, c);
375    }
376}