firewire_dice_protocols/
tcat.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! Protocol defined by TCAT for ASICs of DICE.
5//!
6//! The module includes structure, enumeration, and trait and its implementation for protocol defined
7//! by TC Applied Technologies (TCAT) for ASICs of Digital Interface Communication Engine (DICE).
8//!
9//! In the protocol, all of features are categorized to several parts. Each part is represented in
10//! range of registers accessible by IEEE 1394 asynchronous transaction. In the crate, the range
11//! is called as `section`, therefore the features are categorized to the section.
12
13pub mod ext_sync_section;
14pub mod global_section;
15pub mod rx_stream_format_section;
16pub mod tx_stream_format_section;
17
18pub mod extension;
19pub mod tcd22xx_spec;
20
21pub mod config_rom;
22
23use {
24    super::*,
25    glib::{error::ErrorDomain, Quark},
26    hinawa::{prelude::FwReqExtManual, FwTcode},
27    std::fmt::Debug,
28};
29
30pub use {
31    ext_sync_section::ExtendedSyncParameters,
32    global_section::{GlobalParameters, TcatGlobalSectionSpecification},
33    rx_stream_format_section::RxStreamFormatParameters,
34    tx_stream_format_section::TxStreamFormatParameters,
35};
36
37/// Section in control and status register (CSR) of node.
38#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
39pub struct Section {
40    /// The offset of section in specific address space.
41    pub offset: usize,
42    /// The size of section.
43    pub size: usize,
44}
45
46impl Section {
47    pub(crate) const SIZE: usize = 8;
48}
49
50#[cfg(test)]
51pub(crate) fn serialize_section(section: &Section, raw: &mut [u8]) -> Result<(), String> {
52    assert!(raw.len() >= Section::SIZE);
53
54    let val = (section.offset as u32) / 4;
55    serialize_u32(&val, &mut raw[..4]);
56
57    let val = (section.size as u32) / 4;
58    serialize_u32(&val, &mut raw[4..8]);
59
60    Ok(())
61}
62
63pub(crate) fn deserialize_section(section: &mut Section, raw: &[u8]) -> Result<(), String> {
64    assert!(raw.len() >= Section::SIZE);
65
66    let mut val = 0u32;
67    deserialize_u32(&mut val, &raw[..4]);
68    section.offset = 4 * val as usize;
69
70    deserialize_u32(&mut val, &raw[4..8]);
71    section.size = 4 * val as usize;
72
73    Ok(())
74}
75
76/// The sset of sections in CSR of node.
77#[derive(Default, Debug, Clone, PartialEq, Eq)]
78pub struct GeneralSections {
79    /// For global settings.
80    pub global: Section,
81    /// For tx stream format settings.
82    pub tx_stream_format: Section,
83    /// For rx stream format settings.
84    pub rx_stream_format: Section,
85    /// For extended status of synchronization for signal sources of sampling clock.
86    pub ext_sync: Section,
87    pub reserved: Section,
88}
89
90impl GeneralSections {
91    const SECTION_COUNT: usize = 5;
92    const SIZE: usize = Section::SIZE * Self::SECTION_COUNT;
93}
94
95#[cfg(test)]
96fn serialize_general_sections(sections: &GeneralSections, raw: &mut [u8]) -> Result<(), String> {
97    assert!(raw.len() >= GeneralSections::SIZE);
98
99    serialize_section(&sections.global, &mut raw[..8])?;
100    serialize_section(&sections.tx_stream_format, &mut raw[8..16])?;
101    serialize_section(&sections.rx_stream_format, &mut raw[16..24])?;
102    serialize_section(&sections.ext_sync, &mut raw[24..32])?;
103    serialize_section(&sections.reserved, &mut raw[32..40])?;
104
105    Ok(())
106}
107
108fn deserialize_general_sections(sections: &mut GeneralSections, raw: &[u8]) -> Result<(), String> {
109    assert!(raw.len() >= GeneralSections::SIZE);
110
111    deserialize_section(&mut sections.global, &raw[..8])?;
112    deserialize_section(&mut sections.tx_stream_format, &raw[8..16])?;
113    deserialize_section(&mut sections.rx_stream_format, &raw[16..24])?;
114    deserialize_section(&mut sections.ext_sync, &raw[24..32])?;
115    deserialize_section(&mut sections.reserved, &raw[32..40])?;
116
117    Ok(())
118}
119
120/// Serializer and deserializer for parameters in TCAT section.
121pub trait TcatSectionSerdes<T> {
122    /// Minimum size of section for parameters.
123    const MIN_SIZE: usize;
124
125    /// The type of error.
126    const ERROR_TYPE: GeneralProtocolError;
127
128    /// Serialize parameters for section.
129    fn serialize(params: &T, raw: &mut [u8]) -> Result<(), String>;
130
131    /// Deserialize section for parameters.
132    fn deserialize(params: &mut T, raw: &[u8]) -> Result<(), String>;
133}
134
135/// Any error of general protocol.
136#[derive(Debug, Copy, Clone, PartialEq, Eq)]
137pub enum GeneralProtocolError {
138    /// Error to operate for global settings.
139    Global,
140    /// Error to operate for tx stream format settings.
141    TxStreamFormat,
142    /// Error to operate for rx stream format settings.
143    RxStreamFormat,
144    /// Error to operate for external synchronization states.
145    ExtendedSync,
146    /// Any error in application implementation developed by vendors.
147    VendorDependent,
148    Invalid(i32),
149}
150
151impl std::fmt::Display for GeneralProtocolError {
152    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
153        let msg = match self {
154            GeneralProtocolError::Global => "global",
155            GeneralProtocolError::TxStreamFormat => "tx-stream-format",
156            GeneralProtocolError::RxStreamFormat => "rx-stream-format",
157            GeneralProtocolError::ExtendedSync => "external-sync",
158            GeneralProtocolError::VendorDependent => "vendor-dependent",
159            GeneralProtocolError::Invalid(_) => "invalid",
160        };
161
162        write!(f, "GeneralProtocolError::{}", msg)
163    }
164}
165
166impl ErrorDomain for GeneralProtocolError {
167    fn domain() -> Quark {
168        Quark::from_str("tcat-general-protocol-error-quark")
169    }
170
171    fn code(self) -> i32 {
172        match self {
173            GeneralProtocolError::Global => 0,
174            GeneralProtocolError::TxStreamFormat => 1,
175            GeneralProtocolError::RxStreamFormat => 2,
176            GeneralProtocolError::ExtendedSync => 3,
177            GeneralProtocolError::VendorDependent => 4,
178            GeneralProtocolError::Invalid(v) => v,
179        }
180    }
181
182    fn from(code: i32) -> Option<Self> {
183        let enumeration = match code {
184            0 => GeneralProtocolError::Global,
185            1 => GeneralProtocolError::TxStreamFormat,
186            2 => GeneralProtocolError::RxStreamFormat,
187            3 => GeneralProtocolError::ExtendedSync,
188            4 => GeneralProtocolError::VendorDependent,
189            _ => GeneralProtocolError::Invalid(code),
190        };
191        Some(enumeration)
192    }
193}
194
195const MAX_FRAME_SIZE: usize = 512;
196
197/// Operation of TCAT general protocol.
198pub trait TcatOperation {
199    /// Initiate read transaction to offset in specific address space and finish it.
200    fn read(
201        req: &FwReq,
202        node: &FwNode,
203        offset: usize,
204        mut frames: &mut [u8],
205        timeout_ms: u32,
206    ) -> Result<(), Error> {
207        let mut addr = BASE_ADDR + offset as u64;
208
209        while frames.len() > 0 {
210            let len = std::cmp::min(frames.len(), MAX_FRAME_SIZE);
211            let tcode = if len == 4 {
212                FwTcode::ReadQuadletRequest
213            } else {
214                FwTcode::ReadBlockRequest
215            };
216
217            req.transaction_sync(node, tcode, addr, len, &mut frames[0..len], timeout_ms)?;
218
219            addr += len as u64;
220            frames = &mut frames[len..];
221        }
222
223        Ok(())
224    }
225
226    /// Initiate write transaction to offset in specific address space and finish it.
227    fn write(
228        req: &FwReq,
229        node: &FwNode,
230        offset: usize,
231        mut frames: &mut [u8],
232        timeout_ms: u32,
233    ) -> Result<(), Error> {
234        let mut addr = BASE_ADDR + (offset as u64);
235
236        while frames.len() > 0 {
237            let len = std::cmp::min(frames.len(), MAX_FRAME_SIZE);
238            let tcode = if len == 4 {
239                FwTcode::WriteQuadletRequest
240            } else {
241                FwTcode::WriteBlockRequest
242            };
243
244            req.transaction_sync(node, tcode, addr, len, &mut frames[0..len], timeout_ms)?;
245
246            addr += len as u64;
247            frames = &mut frames[len..];
248        }
249
250        Ok(())
251    }
252
253    /// Read section layout.
254    fn read_general_sections(
255        req: &FwReq,
256        node: &FwNode,
257        sections: &mut GeneralSections,
258        timeout_ms: u32,
259    ) -> Result<(), Error> {
260        let mut raw = [0; GeneralSections::SIZE];
261        Self::read(req, node, 0, &mut raw, timeout_ms)?;
262        deserialize_general_sections(sections, &raw)
263            .map_err(|cause| Error::new(GeneralProtocolError::Invalid(0), &cause))
264    }
265}
266
267fn check_section_cache(
268    section: &Section,
269    min_size: usize,
270    error_type: GeneralProtocolError,
271) -> Result<(), Error> {
272    if section.size < min_size {
273        let msg = format!(
274            "The size of section should be larger than {}, actually {}",
275            min_size, section.size
276        );
277        Err(Error::new(error_type, &msg))
278    } else {
279        Ok(())
280    }
281}
282
283/// Operation for parameters in section of TCAT general protocol.
284pub trait TcatSectionOperation<T>: TcatOperation + TcatSectionSerdes<T>
285where
286    T: Default + Debug,
287{
288    /// Cache whole section and deserialize for parameters.
289    fn whole_cache(
290        req: &FwReq,
291        node: &FwNode,
292        section: &Section,
293        params: &mut T,
294        timeout_ms: u32,
295    ) -> Result<(), Error> {
296        check_section_cache(section, Self::MIN_SIZE, Self::ERROR_TYPE)?;
297        let mut raw = vec![0u8; section.size];
298        Self::read(req, node, section.offset, &mut raw, timeout_ms)?;
299        Self::deserialize(params, &raw).map_err(|msg| Error::new(Self::ERROR_TYPE, &msg))
300    }
301}
302
303/// Operation to change content in section of TCAT general protocol for parameters.
304pub trait TcatMutableSectionOperation<T>: TcatOperation + TcatSectionSerdes<T>
305where
306    T: Default + Debug,
307{
308    /// Update whole section by the parameters.
309    fn whole_update(
310        req: &FwReq,
311        node: &FwNode,
312        section: &Section,
313        params: &T,
314        timeout_ms: u32,
315    ) -> Result<(), Error> {
316        check_section_cache(section, Self::MIN_SIZE, Self::ERROR_TYPE)?;
317        let mut raw = vec![0u8; section.size];
318        Self::serialize(params, &mut raw).map_err(|msg| Error::new(Self::ERROR_TYPE, &msg))?;
319        Self::write(req, node, section.offset, &mut raw, timeout_ms)
320    }
321
322    /// Update part of section for any change at the parameters.
323    fn partial_update(
324        req: &FwReq,
325        node: &FwNode,
326        section: &Section,
327        params: &T,
328        prev: &mut T,
329        timeout_ms: u32,
330    ) -> Result<(), Error> {
331        check_section_cache(section, Self::MIN_SIZE, Self::ERROR_TYPE)?;
332
333        let mut new = vec![0u8; section.size];
334        Self::serialize(params, &mut new).map_err(|msg| Error::new(Self::ERROR_TYPE, &msg))?;
335
336        let mut old = vec![0u8; section.size];
337        Self::serialize(prev, &mut old).map_err(|msg| Error::new(Self::ERROR_TYPE, &msg))?;
338
339        (0..section.size).step_by(4).try_for_each(|pos| {
340            if new[pos..(pos + 4)] != old[pos..(pos + 4)] {
341                Self::write(
342                    req,
343                    node,
344                    section.offset + pos,
345                    &mut new[pos..(pos + 4)],
346                    timeout_ms,
347                )
348            } else {
349                Ok(())
350            }
351        })?;
352
353        Self::deserialize(prev, &new).map_err(|msg| Error::new(Self::ERROR_TYPE, &msg))
354    }
355}
356
357/// Operation for notified parameters in section of TCAT general protocol.
358pub trait TcatNotifiedSectionOperation<T>: TcatSectionOperation<T>
359where
360    T: Default + Debug,
361{
362    /// Flag in message notified for any change in section.
363    const NOTIFY_FLAG: u32;
364
365    /// Check message to be notified or not.
366    fn notified(_: &T, msg: u32) -> bool {
367        msg & Self::NOTIFY_FLAG > 0
368    }
369}
370
371/// Operation for fluctuated content in section of TCAT general protocol.
372pub trait TcatFluctuatedSectionOperation<T>: TcatSectionOperation<T>
373where
374    T: Default + Debug,
375{
376    /// The set of address offsets in which any value is changed apart from software operation;
377    /// e.g. hardware metering.
378    const FLUCTUATED_OFFSETS: &'static [usize];
379
380    /// Cache part of section for fluctuated values, then deserialize for parameters.
381    fn partial_cache(
382        req: &FwReq,
383        node: &FwNode,
384        section: &Section,
385        params: &mut T,
386        timeout_ms: u32,
387    ) -> Result<(), Error> {
388        check_section_cache(section, Self::MIN_SIZE, Self::ERROR_TYPE)?;
389
390        let mut raw = vec![0u8; section.size];
391        Self::serialize(params, &mut raw).map_err(|msg| Error::new(Self::ERROR_TYPE, &msg))?;
392
393        Self::FLUCTUATED_OFFSETS.iter().try_for_each(|&offset| {
394            Self::read(
395                req,
396                node,
397                section.offset + offset,
398                &mut raw[offset..(offset + 4)],
399                timeout_ms,
400            )
401        })?;
402        Self::deserialize(params, &raw).map_err(|msg| Error::new(Self::ERROR_TYPE, &msg))
403    }
404}
405
406const BASE_ADDR: u64 = 0xffffe0000000;
407
408/// Parameter of stream format for IEC 60958.
409#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
410pub struct Iec60958Param {
411    /// The corresponding channel supports IEC 60958 bit stream.
412    pub cap: bool,
413    /// The corresponding channel is enabled for IEC 60958 bit stream.
414    pub enable: bool,
415}
416
417/// The maximum number of IEC 60958 channels for stream format entry.
418pub const IEC60958_CHANNELS: usize = 32;
419
420fn serialize_iec60958_params(
421    params: &[Iec60958Param; IEC60958_CHANNELS],
422    raw: &mut [u8],
423) -> Result<(), String> {
424    assert!(raw.len() >= IEC60958_CHANNELS / 8 * 2);
425
426    let (caps, enables) =
427        params
428            .iter()
429            .enumerate()
430            .fold((0u32, 0u32), |(mut caps, mut enables), (i, params)| {
431                if params.cap {
432                    caps |= 1 << i;
433                }
434                if params.enable {
435                    enables |= 1 << i;
436                }
437                (caps, enables)
438            });
439
440    raw[..4].copy_from_slice(&caps.to_be_bytes());
441    raw[4..8].copy_from_slice(&enables.to_be_bytes());
442
443    Ok(())
444}
445
446fn deserialize_iec60958_params(
447    params: &mut [Iec60958Param; IEC60958_CHANNELS],
448    raw: &[u8],
449) -> Result<(), String> {
450    assert!(raw.len() >= IEC60958_CHANNELS / 8 * 2);
451
452    let mut quadlet = [0; 4];
453
454    quadlet.copy_from_slice(&raw[..4]);
455    let caps = u32::from_be_bytes(quadlet);
456
457    quadlet.copy_from_slice(&raw[4..8]);
458    let enables = u32::from_be_bytes(quadlet);
459
460    params.iter_mut().enumerate().for_each(|(i, param)| {
461        param.cap = (1 << i) & caps > 0;
462        param.enable = (1 << i) & enables > 0;
463    });
464
465    Ok(())
466}
467
468fn from_ne(raw: &mut [u8]) {
469    let mut quadlet = [0; 4];
470    (0..raw.len()).step_by(4).for_each(|pos| {
471        quadlet.copy_from_slice(&raw[pos..(pos + 4)]);
472        raw[pos..(pos + 4)].copy_from_slice(&u32::from_ne_bytes(quadlet).to_be_bytes());
473    });
474}
475
476fn to_ne(raw: &mut [u8]) {
477    let mut quadlet = [0; 4];
478    (0..raw.len()).step_by(4).for_each(|pos| {
479        quadlet.copy_from_slice(&raw[pos..(pos + 4)]);
480        raw[pos..(pos + 4)].copy_from_slice(&u32::from_be_bytes(quadlet).to_ne_bytes());
481    });
482}
483
484fn serialize_label<T: AsRef<str>>(name: T, raw: &mut [u8]) -> Result<(), String> {
485    let r = name.as_ref().as_bytes();
486
487    if r.len() >= raw.len() {
488        Err(format!("Insufficient buffer size {} for label", raw.len()))
489    } else {
490        raw[..r.len()].copy_from_slice(r);
491        from_ne(raw);
492
493        Ok(())
494    }
495}
496
497fn serialize_labels<T: AsRef<str>>(labels: &[T], raw: &mut [u8]) -> Result<(), String> {
498    raw.fill(0x00);
499
500    let mut pos = 0;
501    labels.iter().try_for_each(|label| {
502        let r = label.as_ref().as_bytes();
503
504        if pos + r.len() + 1 >= raw.len() {
505            Err(format!(
506                "Insufficient buffer size {} for all of labels",
507                raw.len()
508            ))
509        } else {
510            let end = pos + r.len();
511            raw[pos..end].copy_from_slice(r);
512
513            raw[end] = '\\' as u8;
514            pos = end + 1;
515
516            Ok(())
517        }
518    })?;
519
520    if pos + 1 >= raw.len() {
521        Err(format!(
522            "Insufficient buffer size {} for all of labels",
523            raw.len()
524        ))
525    } else {
526        raw[pos] = '\\' as u8;
527
528        from_ne(raw);
529
530        Ok(())
531    }
532}
533
534fn deserialize_label(label: &mut String, raw: &[u8]) -> Result<(), String> {
535    let mut data = raw.to_vec();
536    to_ne(&mut data);
537
538    data.push(0x00);
539    std::str::from_utf8(&data)
540        .map_err(|err| err.to_string())
541        .and_then(|text| {
542            text.find('\0')
543                .ok_or_else(|| "String terminator not found".to_string())
544                .map(|pos| *label = text[..pos].to_string())
545        })
546}
547
548fn deserialize_labels(labels: &mut Vec<String>, raw: &[u8]) -> Result<(), String> {
549    labels.truncate(0);
550
551    let mut data = raw.to_vec();
552    to_ne(&mut data);
553
554    data.split(|&b| b == '\\' as u8)
555        .filter(|chunk| chunk.len() > 0 && chunk[0] != '\0' as u8)
556        .fuse()
557        .try_for_each(|chunk| {
558            std::str::from_utf8(&chunk)
559                .map(|label| labels.push(label.to_string()))
560                .map_err(|err| err.to_string())
561        })
562}
563
564const NOTIFY_RX_CFG_CHG: u32 = 0x00000001;
565const NOTIFY_TX_CFG_CHG: u32 = 0x00000002;
566const NOTIFY_LOCK_CHG: u32 = 0x00000010;
567const NOTIFY_CLOCK_ACCEPTED: u32 = 0x00000020;
568const NOTIFY_EXT_STATUS: u32 = 0x00000040;
569
570#[cfg(test)]
571mod test {
572    use super::*;
573
574    #[test]
575    fn label_serdes() {
576        let label = "label-0";
577
578        let mut raw = vec![0u8; 20];
579        serialize_label(&label, &mut raw).unwrap();
580
581        let mut l = String::new();
582        deserialize_label(&mut l, &raw).unwrap();
583
584        assert_eq!(label, l);
585    }
586
587    #[test]
588    fn labels_serdes() {
589        let labels: Vec<String> = (0..10).map(|num| format!("label-{}", num)).collect();
590
591        let mut raw = vec![0u8; 100];
592        serialize_labels(&labels, &mut raw).unwrap();
593
594        let mut l = Vec::new();
595        deserialize_labels(&mut l, &raw).unwrap();
596
597        assert_eq!(labels, l);
598    }
599
600    #[test]
601    fn sections_serdes() {
602        let raw = [
603            0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00,
604            0x00, 0x8e, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x00, 0x02, 0x11,
605            0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
606        ];
607        let mut params = GeneralSections::default();
608        deserialize_general_sections(&mut params, &raw).unwrap();
609
610        assert_eq!(params.global.offset, 0x28);
611        assert_eq!(params.global.size, 0x17c);
612        assert_eq!(params.tx_stream_format.offset, 0x1a4);
613        assert_eq!(params.tx_stream_format.size, 0x238);
614        assert_eq!(params.rx_stream_format.offset, 0x3dc);
615        assert_eq!(params.rx_stream_format.size, 0x468);
616        assert_eq!(params.ext_sync.offset, 0x844);
617        assert_eq!(params.ext_sync.size, 0x10);
618        assert_eq!(params.reserved.offset, 0);
619        assert_eq!(params.reserved.size, 0);
620
621        let mut r = vec![0u8; raw.len()];
622        serialize_general_sections(&params, &mut r).unwrap();
623
624        assert_eq!(r, raw);
625    }
626}