firewire_dice_protocols/tcat/extension/
caps_section.rs1use super::*;
9
10#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
12pub struct RouterCaps {
13 pub is_exposed: bool,
15 pub is_readonly: bool,
17 pub is_storable: bool,
19 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#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
72pub struct MixerCaps {
73 pub is_exposed: bool,
75 pub is_readonly: bool,
77 pub is_storable: bool,
79 pub input_device_id: u8,
81 pub output_device_id: u8,
83 pub input_count: u8,
85 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#[derive(Debug, Copy, Clone, PartialEq, Eq)]
157pub enum AsicType {
158 DiceII,
160 Tcd2210,
162 Tcd2220,
164}
165
166impl Default for AsicType {
167 fn default() -> Self {
168 AsicType::DiceII
169 }
170}
171
172#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
174pub struct GeneralCaps {
175 pub dynamic_stream_format: bool,
177 pub storage_avail: bool,
179 pub peak_avail: bool,
181 pub max_tx_streams: u8,
183 pub max_rx_streams: u8,
185 pub stream_format_is_storable: bool,
187 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#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
273pub struct ExtensionCaps {
274 pub router: RouterCaps,
276 pub mixer: MixerCaps,
278 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(¶ms.router, &mut raw[..4])?;
287 serialize_mixer_caps(¶ms.mixer, &mut raw[4..8])?;
288 serialize_general_caps(¶ms.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
310pub trait TcatExtensionCapsSectionOperation: TcatExtensionOperation {
312 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, §ions.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}