firewire_motu_protocols/
version_1.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2021 Takashi Sakamoto
3
4//! Protocol used in version 1 devices of MOTU FireWire series.
5//!
6//! The modules includes structure, enumeration, and trait and its implementation for protocol
7//! used in version 1 devices of Mark of the Unicorn FireWire series.
8
9use super::*;
10
11/// Signal source of sampling clock.
12#[derive(Debug, Copy, Clone, PartialEq, Eq)]
13pub enum V1ClkSrc {
14    /// Internal.
15    Internal,
16    /// S/PDIF on coaxial or optical interface.
17    Spdif,
18    /// Word clock on BNC interface.
19    WordClk,
20    /// ADAT on optical interface.
21    AdatOpt,
22    /// ADAT on D-Sub interface.
23    AdatDsub,
24    /// AES/EBU on XLR interface.
25    AesebuXlr,
26}
27
28impl Default for V1ClkSrc {
29    fn default() -> Self {
30        Self::Internal
31    }
32}
33
34/// Mode of optical interface.
35#[derive(Debug, Copy, Clone, PartialEq, Eq)]
36pub enum V1OptIfaceMode {
37    Adat,
38    Spdif,
39}
40
41impl Default for V1OptIfaceMode {
42    fn default() -> Self {
43        Self::Adat
44    }
45}
46
47// 828 registers:
48//
49// 0x'ffff'f000'0b00: configuration for sampling clock and digital interfaces.
50//
51//  0xffff0000: communication control. ALSA firewire-motu driver changes it.
52//  0x00008000: mode of optical input interface.
53//    0x00008000: for S/PDIF signal.
54//    0x00000000: disabled or for ADAT signal.
55//  0x00004000: mode of optical output interface.
56//    0x00004000: for S/PDIF signal.
57//    0x00000000: disabled or for ADAT signal.
58//  0x00003f00: monitor input mode.
59//    0x00000800: analog-1/2
60//    0x00001a00: analog-3/4
61//    0x00002c00: analog-5/6
62//    0x00003e00: analog-7/8
63//    0x00000000: analog-1
64//    0x00000900: analog-2
65//    0x00001200: analog-3
66//    0x00001b00: analog-4
67//    0x00002400: analog-5
68//    0x00002d00: analog-6
69//    0x00003600: analog-7
70//    0x00003f00: analog-8
71//  0x00000080: enable stream input.
72//  0x00000040: disable monitor input.
73//  0x00000008: enable main out.
74//  0x00000004: rate of sampling clock.
75//    0x00000004: 48.0 kHz
76//    0x00000000: 44.1 kHz
77//  0x00000023: source of sampling clock.
78//    0x00000003: source packet header (SPH)
79//    0x00000002: S/PDIF on optical/coaxial interface.
80//    0x00000021: ADAT on optical interface
81//    0x00000001: ADAT on Dsub 9pin
82//    0x00000000: internal
83
84const CONF_828_OFFSET: u32 = 0x00000b00;
85
86const CONF_828_OPT_IN_IFACE_MASK: u32 = 0x00008000;
87const CONF_828_OPT_IN_IFACE_SHIFT: usize = 15;
88
89const CONF_828_OPT_OUT_IFACE_MASK: u32 = 0x00004000;
90const CONF_828_OPT_OUT_IFACE_SHIFT: usize = 14;
91
92const CONF_828_OPT_IFACE_VALS: [u8; 2] = [0x00, 0x01];
93
94const CONF_828_MONITOR_INPUT_CH_MASK: u32 = 0x00003f00;
95const CONF_828_MONITOR_INPUT_CH_SHIFT: usize = 8;
96const CONF_828_MONITOR_INPUT_CH_VALS: &[u8] = &[
97    0x08, // 0/1
98    0x1a, // 2/3
99    0x2c, // 4/5
100    0x3e, // 6/7
101    0x00, // 0
102    0x09, // 1
103    0x12, // 2
104    0x1b, // 3
105    0x24, // 4
106    0x2d, // 5
107    0x36, // 6
108    0x3f, // 7
109];
110
111const CONF_828_STREAM_INPUT_ENABLE_MASK: u32 = 0x00000080;
112
113const CONF_828_MONITOR_INPUT_DISABLE_MASK: u32 = 0x00000040;
114
115const CONF_828_OUTPUT_ENABLE_MASK: u32 = 0x00000008;
116
117const CONF_828_CLK_RATE_MASK: u32 = 0x00000004;
118const CONF_828_CLK_RATE_SHIFT: usize = 2;
119
120const CONF_828_CLK_SRC_MASK: u32 = 0x00000023;
121const CONF_828_CLK_SRC_SHIFT: usize = 0;
122
123//
124// 896 registers:
125//
126// 0x'ffff'f000'0b14: configuration for sampling clock and input source for main output.
127//  0xf0000000: enable physical and stream input to DAC.
128//    0x80000000: disable
129//    0x40000000: disable
130//    0x20000000: enable (prior to the other bits)
131//    0x10000000: disable
132//    0x00000000: disable
133//  0x08000000: speed of word clock signal output on BNC interface.
134//    0x00000000: force to low rate (44.1/48.0 kHz).
135//    0x08000000: follow to system clock.
136//  0x04000000: something relevant to clock.
137//  0x03000000: enable output.
138//   0x02000000: enabled irreversibly once standing
139//   0x01000000: enabled irreversibly once standing
140//  0x00ffff00: input to monitor.
141//    0x00000000: none
142//    0x00004800: analog-1/2
143//    0x00005a00: analog-3/4
144//    0x00006c00: analog-5/6
145//    0x00007e00: analog-7/8
146//    0x00104800: AES/EBU-1/2
147//    0x00004000: analog-1
148//    0x00004900: analog-2
149//    0x00005200: analog-3
150//    0x00005b00: analog-4
151//    0x00006400: analog-5
152//    0x00006d00: analog-6
153//    0x00007600: analog-7
154//    0x00007f00: analog-8
155//    0x00104000: AES/EBU-1
156//    0x00104900: AES/EBU-2
157//  0x00000060: sample rate conversion for AES/EBU input/output.
158//    0x00000000: None
159//    0x00000020: input signal is converted to system rate
160//    0x00000040: output is slave to input, ignoring system rate
161//    0x00000060: output is double rate than system rate
162//  0x00000018: nominal rate of sampling clock.
163//    0x00000000: 44.1 kHz
164//    0x00000008: 48.0 kHz
165//    0x00000010: 88.2 kHz
166//    0x00000018: 96.0 kHz
167//  0x00000007: source of sampling clock.
168//    0x00000000: internal
169//    0x00000001: ADAT on optical interface
170//    0x00000002: AES/EBU on XLR
171//    0x00000003: source packet header (SPH)
172//    0x00000004: word clock on BNC
173//    0x00000005: ADAT on Dsub 9pin
174//
175// 0x'ffff'f000'0b24: configuration for meter and stream source for main output.
176//  0x00004000: LED carnival.
177//  0x00003800: peak hold time.
178//   0x00003800: infinite
179//   0x00003000: 480 sec
180//   0x00002800: 300 sec
181//   0x00002000: 60 sec
182//   0x00001800: 10 sec
183//   0x00001000: 4 sec
184//   0x00000800: 2 sec
185//   0x00000000: disabled
186//  0x00000700: clip hold time.
187//   0x00000700: infinite
188//   0x00000600: 480 sec
189//   0x00000500: 300 sec
190//   0x00000400: 60 sec
191//   0x00000300: 10 sec
192//   0x00000200: 4 sec
193//   0x00000100: 2 sec
194//   0x00000000: disabled
195//  0x000000f0: stream source to main output.
196//   0x00000080: Stream-16/17
197//   0x00000080: Stream-16/17
198//   0x00000070: (mute)
199//   0x00000060: (mute)
200//   0x00000050: (mute)
201//   0x00000040: (mute)
202//   0x00000030: Stream-6/7
203//   0x00000020: Stream-4/5
204//   0x00000010: Stream-2/3
205//   0x00000000: Stream-0/1
206//  0x00000004: The target of AES/EBU meter.
207//   0x00000001: AES/EBU input
208//   0x00000000: AES/EBU output.
209//  0x00000003: The target of programmable meter.
210//   0x00000002: ADAT output
211//   0x00000001: ADAT input
212//   0x00000000: Analog output
213
214const CONF_896_MONITOR_INPUT_AESEBU_MASK: u32 = 0x00100000;
215const CONF_896_MONITOR_INPUT_AESEBU_SHIFT: usize = 20;
216const CONF_896_MONITOR_INPUT_CH_VALS: &[u8] = &[
217    0x00, // disabled
218    0x48, // 1/2
219    0x5a, // 3/4
220    0x6c, // 5/6
221    0x7e, // 7/8
222    0x40, // 1
223    0x49, // 2
224    0x52, // 3
225    0x5b, // 4
226    0x64, // 5
227    0x6d, // 6
228    0x76, // 7
229    0x7f, // 8
230];
231
232const CONF_896_MONITOR_INPUT_CH_MASK: u32 = 0x0000ff00;
233const CONF_896_MONITOR_INPUT_CH_SHIFT: usize = 8;
234const CONF_896_MONITOR_INPUT_VALS: &[(usize, usize)] = &[
235    (0, 0),
236    (1, 0),
237    (2, 0),
238    (3, 0),
239    (4, 0),
240    (1, 1),
241    (5, 0),
242    (6, 0),
243    (7, 0),
244    (8, 0),
245    (9, 0),
246    (10, 0),
247    (11, 0),
248    (12, 0),
249    (5, 1),
250];
251
252const CONF_896_CLK_RATE_MASK: u32 = 0x00000018;
253const CONF_896_CLK_RATE_SHIFT: usize = 3;
254
255const CONF_896_CLK_SRC_MASK: u32 = 0x00000007;
256const CONF_896_CLK_SRC_SHIFT: usize = 0;
257
258const CLK_RATE_LABEL: &str = "clock-rate-v1";
259const CLK_SRC_LABEL: &str = "clock-source-v1";
260
261/// The parameters of media and sampling clock.
262#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
263pub struct Version1ClockParameters {
264    /// The rate of media clock.
265    pub rate: ClkRate,
266    /// The source of sampling clock.
267    pub source: V1ClkSrc,
268}
269
270/// The trait for specification of sampling and media clock in version 1 protocol.
271pub trait MotuVersion1ClockSpecification {
272    const CLK_OFFSET: u32;
273
274    const CLK_RATE_MASK: u32;
275    const CLK_RATE_SHIFT: usize;
276    const CLK_RATE_VALS: &'static [u8];
277    const CLK_RATES: &'static [ClkRate];
278
279    const CLK_SRC_MASK: u32;
280    const CLK_SRC_SHIFT: usize;
281    const CLK_SRC_VALS: &'static [u8];
282    const CLK_SRCS: &'static [V1ClkSrc];
283}
284
285impl<O> MotuWhollyCacheableParamsOperation<Version1ClockParameters> for O
286where
287    O: MotuVersion1ClockSpecification,
288{
289    fn cache_wholly(
290        req: &mut FwReq,
291        node: &mut FwNode,
292        params: &mut Version1ClockParameters,
293        timeout_ms: u32,
294    ) -> Result<(), Error> {
295        let quad = read_quad(req, node, Self::CLK_OFFSET, timeout_ms)?;
296
297        deserialize_flag(
298            &mut params.rate,
299            &quad,
300            Self::CLK_RATE_MASK,
301            Self::CLK_RATE_SHIFT,
302            Self::CLK_RATES,
303            Self::CLK_RATE_VALS,
304            CLK_RATE_LABEL,
305        )?;
306
307        deserialize_flag(
308            &mut params.source,
309            &quad,
310            Self::CLK_SRC_MASK,
311            Self::CLK_SRC_SHIFT,
312            Self::CLK_SRCS,
313            Self::CLK_SRC_VALS,
314            CLK_SRC_LABEL,
315        )
316    }
317}
318
319impl<O> MotuWhollyUpdatableParamsOperation<Version1ClockParameters> for O
320where
321    O: MotuVersion1ClockSpecification,
322{
323    fn update_wholly(
324        req: &mut FwReq,
325        node: &mut FwNode,
326        params: &Version1ClockParameters,
327        timeout_ms: u32,
328    ) -> Result<(), Error> {
329        let mut quad = read_quad(req, node, Self::CLK_OFFSET, timeout_ms)?;
330
331        serialize_flag(
332            &params.rate,
333            &mut quad,
334            Self::CLK_RATE_MASK,
335            Self::CLK_RATE_SHIFT,
336            Self::CLK_RATES,
337            Self::CLK_RATE_VALS,
338            CLK_RATE_LABEL,
339        )?;
340
341        serialize_flag(
342            &params.source,
343            &mut quad,
344            Self::CLK_SRC_MASK,
345            Self::CLK_SRC_SHIFT,
346            Self::CLK_SRCS,
347            Self::CLK_SRC_VALS,
348            CLK_SRC_LABEL,
349        )?;
350
351        write_quad(req, node, Self::CLK_OFFSET, quad, timeout_ms)
352    }
353}
354
355/// The parameters of monitor inputs.
356#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
357pub struct Version1MonitorInputParameters(pub TargetPort);
358
359/// The trait for specification of monitor input.
360pub trait MotuVersion1MonitorInputSpecification {
361    const MONITOR_INPUT_MODES: &'static [TargetPort];
362}
363
364const MONITOR_INPUT_CH_LABEL: &str = "monitor-input-ch-v1";
365
366/// The protocol implementation for 828.
367#[derive(Default)]
368pub struct F828Protocol;
369
370impl MotuVersion1ClockSpecification for F828Protocol {
371    const CLK_OFFSET: u32 = CONF_828_OFFSET;
372
373    const CLK_RATE_MASK: u32 = CONF_828_CLK_RATE_MASK;
374    const CLK_RATE_SHIFT: usize = CONF_828_CLK_RATE_SHIFT;
375    const CLK_RATE_VALS: &'static [u8] = &[0x00, 0x01];
376    const CLK_RATES: &'static [ClkRate] = &[ClkRate::R44100, ClkRate::R48000];
377
378    const CLK_SRC_MASK: u32 = CONF_828_CLK_SRC_MASK;
379    const CLK_SRC_SHIFT: usize = CONF_828_CLK_SRC_SHIFT;
380    const CLK_SRC_VALS: &'static [u8] = &[0x00, 0x01, 0x02, 0x21];
381    const CLK_SRCS: &'static [V1ClkSrc] = &[
382        V1ClkSrc::Internal,
383        V1ClkSrc::AdatDsub,
384        V1ClkSrc::Spdif,
385        V1ClkSrc::AdatOpt,
386    ];
387}
388
389impl MotuVersion1MonitorInputSpecification for F828Protocol {
390    const MONITOR_INPUT_MODES: &'static [TargetPort] = &[
391        TargetPort::Disabled,
392        TargetPort::AnalogPair(0),
393        TargetPort::AnalogPair(1),
394        TargetPort::AnalogPair(2),
395        TargetPort::AnalogPair(3),
396        TargetPort::Analog(0),
397        TargetPort::Analog(1),
398        TargetPort::Analog(2),
399        TargetPort::Analog(3),
400        TargetPort::Analog(4),
401        TargetPort::Analog(5),
402        TargetPort::Analog(6),
403        TargetPort::Analog(7),
404    ];
405}
406
407impl MotuWhollyCacheableParamsOperation<Version1MonitorInputParameters> for F828Protocol {
408    fn cache_wholly(
409        req: &mut FwReq,
410        node: &mut FwNode,
411        params: &mut Version1MonitorInputParameters,
412        timeout_ms: u32,
413    ) -> Result<(), Error> {
414        let quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
415
416        if quad & CONF_828_MONITOR_INPUT_DISABLE_MASK > 0 {
417            params.0 = TargetPort::Disabled;
418            Ok(())
419        } else {
420            deserialize_flag(
421                &mut params.0,
422                &quad,
423                CONF_828_MONITOR_INPUT_CH_MASK,
424                CONF_828_MONITOR_INPUT_CH_SHIFT,
425                &Self::MONITOR_INPUT_MODES[1..],
426                CONF_828_MONITOR_INPUT_CH_VALS,
427                MONITOR_INPUT_CH_LABEL,
428            )
429        }
430    }
431}
432
433impl MotuWhollyUpdatableParamsOperation<Version1MonitorInputParameters> for F828Protocol {
434    fn update_wholly(
435        req: &mut FwReq,
436        node: &mut FwNode,
437        params: &Version1MonitorInputParameters,
438        timeout_ms: u32,
439    ) -> Result<(), Error> {
440        if Self::MONITOR_INPUT_MODES
441            .iter()
442            .find(|m| params.0.eq(m))
443            .is_none()
444        {
445            let msg = format!("{:?} is not supported for monitor input", params.0);
446            Err(Error::new(FileError::Inval, &msg))?;
447        }
448
449        let mut quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
450
451        if params.0 == TargetPort::Disabled {
452            quad |= CONF_828_MONITOR_INPUT_DISABLE_MASK;
453        } else {
454            quad &= !CONF_828_MONITOR_INPUT_DISABLE_MASK;
455            serialize_flag(
456                &params.0,
457                &mut quad,
458                CONF_828_MONITOR_INPUT_CH_MASK,
459                CONF_828_MONITOR_INPUT_CH_SHIFT,
460                &<F828Protocol as MotuVersion1MonitorInputSpecification>::MONITOR_INPUT_MODES[1..],
461                CONF_828_MONITOR_INPUT_CH_VALS,
462                MONITOR_INPUT_CH_LABEL,
463            )?;
464        }
465
466        write_quad(req, node, CONF_828_OFFSET, quad, timeout_ms)
467    }
468}
469
470/// The parameter of optical interface for 828.
471#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
472pub struct F828OpticalIfaceParameters {
473    /// The mode of signal in optical input interface.
474    pub input_mode: V1OptIfaceMode,
475    /// The mode of signal in optical output interface.
476    pub output_mode: V1OptIfaceMode,
477}
478
479const CONF_828_OPT_OUT_IFACE_LABEL: &str = "opt-out-iface-v1";
480const CONF_828_OPT_IN_IFACE_LABEL: &str = "opt-in-iface-v1";
481
482impl F828Protocol {
483    /// The available modes of optical interface.
484    pub const OPT_IFACE_MODES: &[V1OptIfaceMode] = &[V1OptIfaceMode::Adat, V1OptIfaceMode::Spdif];
485}
486
487impl MotuWhollyCacheableParamsOperation<F828OpticalIfaceParameters> for F828Protocol {
488    fn cache_wholly(
489        req: &mut FwReq,
490        node: &mut FwNode,
491        params: &mut F828OpticalIfaceParameters,
492        timeout_ms: u32,
493    ) -> Result<(), Error> {
494        let quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
495
496        deserialize_flag(
497            &mut params.input_mode,
498            &quad,
499            CONF_828_OPT_IN_IFACE_MASK,
500            CONF_828_OPT_IN_IFACE_SHIFT,
501            Self::OPT_IFACE_MODES,
502            &CONF_828_OPT_IFACE_VALS,
503            CONF_828_OPT_IN_IFACE_LABEL,
504        )?;
505
506        deserialize_flag(
507            &mut params.output_mode,
508            &quad,
509            CONF_828_OPT_OUT_IFACE_MASK,
510            CONF_828_OPT_OUT_IFACE_SHIFT,
511            Self::OPT_IFACE_MODES,
512            &CONF_828_OPT_IFACE_VALS,
513            CONF_828_OPT_OUT_IFACE_LABEL,
514        )
515    }
516}
517
518impl MotuWhollyUpdatableParamsOperation<F828OpticalIfaceParameters> for F828Protocol {
519    fn update_wholly(
520        req: &mut FwReq,
521        node: &mut FwNode,
522        params: &F828OpticalIfaceParameters,
523        timeout_ms: u32,
524    ) -> Result<(), Error> {
525        let mut quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
526
527        serialize_flag(
528            &params.input_mode,
529            &mut quad,
530            CONF_828_OPT_IN_IFACE_MASK,
531            CONF_828_OPT_IN_IFACE_SHIFT,
532            Self::OPT_IFACE_MODES,
533            &CONF_828_OPT_IFACE_VALS,
534            CONF_828_OPT_IN_IFACE_LABEL,
535        )?;
536
537        serialize_flag(
538            &params.output_mode,
539            &mut quad,
540            CONF_828_OPT_OUT_IFACE_MASK,
541            CONF_828_OPT_OUT_IFACE_SHIFT,
542            Self::OPT_IFACE_MODES,
543            &CONF_828_OPT_IFACE_VALS,
544            CONF_828_OPT_OUT_IFACE_LABEL,
545        )?;
546
547        write_quad(req, node, CONF_828_OFFSET, quad, timeout_ms)
548    }
549}
550
551/// The parameter of stream input for 828.
552#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
553pub struct F828StreamInputParameters(pub bool);
554
555impl MotuWhollyCacheableParamsOperation<F828StreamInputParameters> for F828Protocol {
556    fn cache_wholly(
557        req: &mut FwReq,
558        node: &mut FwNode,
559        params: &mut F828StreamInputParameters,
560        timeout_ms: u32,
561    ) -> Result<(), Error> {
562        let quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
563
564        params.0 = quad & CONF_828_STREAM_INPUT_ENABLE_MASK > 0;
565
566        Ok(())
567    }
568}
569
570impl MotuWhollyUpdatableParamsOperation<F828StreamInputParameters> for F828Protocol {
571    fn update_wholly(
572        req: &mut FwReq,
573        node: &mut FwNode,
574        params: &F828StreamInputParameters,
575        timeout_ms: u32,
576    ) -> Result<(), Error> {
577        let mut quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
578
579        quad &= !CONF_828_STREAM_INPUT_ENABLE_MASK;
580        if params.0 {
581            quad |= CONF_828_STREAM_INPUT_ENABLE_MASK;
582        }
583
584        write_quad(req, node, CONF_828_OFFSET, quad, timeout_ms)
585    }
586}
587
588/// The parameter of output for 828.
589#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
590pub struct F828OutputParameters(pub bool);
591
592impl MotuWhollyCacheableParamsOperation<F828OutputParameters> for F828Protocol {
593    fn cache_wholly(
594        req: &mut FwReq,
595        node: &mut FwNode,
596        params: &mut F828OutputParameters,
597        timeout_ms: u32,
598    ) -> Result<(), Error> {
599        let quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
600
601        params.0 = quad & CONF_828_OUTPUT_ENABLE_MASK > 0;
602
603        Ok(())
604    }
605}
606
607impl MotuWhollyUpdatableParamsOperation<F828OutputParameters> for F828Protocol {
608    fn update_wholly(
609        req: &mut FwReq,
610        node: &mut FwNode,
611        params: &F828OutputParameters,
612        timeout_ms: u32,
613    ) -> Result<(), Error> {
614        let mut quad = read_quad(req, node, CONF_828_OFFSET, timeout_ms)?;
615
616        quad &= !CONF_828_OUTPUT_ENABLE_MASK;
617        if params.0 {
618            quad |= CONF_828_OUTPUT_ENABLE_MASK;
619        }
620
621        write_quad(req, node, CONF_828_OFFSET, quad, timeout_ms)
622    }
623}
624
625/// The protocol implementation for 896.
626#[derive(Default)]
627pub struct F896Protocol;
628
629impl F896Protocol {
630    /// Notification mask for footswitch.
631    pub const NOTIFY_FOOTSWITCH_MASK: u32 = 0x01000000;
632}
633
634impl MotuWordClockOutputSpecification for F896Protocol {}
635
636impl MotuVersion1ClockSpecification for F896Protocol {
637    const CLK_OFFSET: u32 = OFFSET_CLK;
638
639    const CLK_RATE_MASK: u32 = CONF_896_CLK_RATE_MASK;
640    const CLK_RATE_SHIFT: usize = CONF_896_CLK_RATE_SHIFT;
641    const CLK_RATE_VALS: &'static [u8] = &[0x00, 0x01, 0x02, 0x03];
642    const CLK_RATES: &'static [ClkRate] = &[
643        ClkRate::R44100,
644        ClkRate::R48000,
645        ClkRate::R88200,
646        ClkRate::R96000,
647    ];
648
649    const CLK_SRC_MASK: u32 = CONF_896_CLK_SRC_MASK;
650    const CLK_SRC_SHIFT: usize = CONF_896_CLK_SRC_SHIFT;
651    const CLK_SRC_VALS: &'static [u8] = &[0x00, 0x01, 0x02, 0x04, 0x05];
652    const CLK_SRCS: &'static [V1ClkSrc] = &[
653        V1ClkSrc::Internal,
654        V1ClkSrc::AdatOpt,
655        V1ClkSrc::AesebuXlr,
656        V1ClkSrc::WordClk,
657        V1ClkSrc::AdatDsub,
658    ];
659}
660
661impl MotuVersion1MonitorInputSpecification for F896Protocol {
662    const MONITOR_INPUT_MODES: &'static [TargetPort] = &[
663        TargetPort::Disabled,
664        TargetPort::AnalogPair(0),
665        TargetPort::AnalogPair(1),
666        TargetPort::AnalogPair(2),
667        TargetPort::AnalogPair(3),
668        TargetPort::AesEbuPair,
669        TargetPort::Analog(0),
670        TargetPort::Analog(1),
671        TargetPort::Analog(2),
672        TargetPort::Analog(3),
673        TargetPort::Analog(4),
674        TargetPort::Analog(5),
675        TargetPort::Analog(6),
676        TargetPort::Analog(7),
677        TargetPort::AesEbu(0),
678        TargetPort::AesEbu(1),
679    ];
680}
681
682impl MotuWhollyCacheableParamsOperation<Version1MonitorInputParameters> for F896Protocol {
683    fn cache_wholly(
684        req: &mut FwReq,
685        node: &mut FwNode,
686        params: &mut Version1MonitorInputParameters,
687        timeout_ms: u32,
688    ) -> Result<(), Error> {
689        let quad = read_quad(req, node, OFFSET_CLK, timeout_ms)?;
690
691        let aesebu_idx = ((quad & CONF_896_MONITOR_INPUT_AESEBU_MASK)
692            >> CONF_896_MONITOR_INPUT_AESEBU_SHIFT) as usize;
693        let ch_idx =
694            ((quad & CONF_896_MONITOR_INPUT_CH_MASK) >> CONF_896_MONITOR_INPUT_CH_SHIFT) as usize;
695
696        Self::MONITOR_INPUT_MODES
697            .iter()
698            .zip(CONF_896_MONITOR_INPUT_VALS)
699            .find(|(_, entry)| (ch_idx, aesebu_idx).eq(entry))
700            .ok_or_else(|| {
701                let label = "Detect invalid value for monitor input";
702                Error::new(FileError::Io, &label)
703            })
704            .map(|(&mode, _)| params.0 = mode)
705    }
706}
707
708impl MotuWhollyUpdatableParamsOperation<Version1MonitorInputParameters> for F896Protocol {
709    fn update_wholly(
710        req: &mut FwReq,
711        node: &mut FwNode,
712        params: &Version1MonitorInputParameters,
713        timeout_ms: u32,
714    ) -> Result<(), Error> {
715        let (ch_idx, aesebu_idx) = Self::MONITOR_INPUT_MODES
716            .iter()
717            .zip(CONF_896_MONITOR_INPUT_VALS)
718            .find(|(m, _)| params.0.eq(m))
719            .ok_or_else(|| {
720                let msg = format!("{:?} is not supported for monitor input", params.0);
721                Error::new(FileError::Io, &msg)
722            })
723            .map(|(_, &entry)| entry)?;
724
725        let mut quad = read_quad(req, node, OFFSET_CLK, timeout_ms)?;
726
727        quad &= !CONF_896_MONITOR_INPUT_AESEBU_MASK;
728        if aesebu_idx > 0 {
729            quad |= (aesebu_idx as u32) << CONF_896_MONITOR_INPUT_AESEBU_SHIFT;
730        }
731
732        quad &= !CONF_896_MONITOR_INPUT_CH_MASK;
733        quad |= (CONF_896_MONITOR_INPUT_CH_VALS[ch_idx] as u32) << CONF_896_MONITOR_INPUT_CH_SHIFT;
734
735        write_quad(req, node, OFFSET_CLK, quad, timeout_ms)
736    }
737}
738
739impl MotuAesebuRateConvertSpecification for F896Protocol {
740    const AESEBU_RATE_CONVERT_MASK: u32 = 0x00000060;
741    const AESEBU_RATE_CONVERT_SHIFT: usize = 5;
742}
743
744impl MotuLevelMetersSpecification for F896Protocol {
745    const LEVEL_METERS_PROGRAMMABLE_MODES: &'static [LevelMetersProgrammableMode] = &[
746        LevelMetersProgrammableMode::AnalogOutput,
747        LevelMetersProgrammableMode::AdatAInput,
748        LevelMetersProgrammableMode::AdatAOutput,
749    ];
750}
751
752#[cfg(test)]
753mod test {
754    use super::*;
755
756    #[test]
757    fn v1_clock_specification() {
758        assert_eq!(
759            F828Protocol::CLK_RATE_VALS.len(),
760            F828Protocol::CLK_RATES.len()
761        );
762        assert_eq!(
763            F828Protocol::CLK_SRC_VALS.len(),
764            F828Protocol::CLK_SRCS.len()
765        );
766
767        assert_eq!(
768            F896Protocol::CLK_RATE_VALS.len(),
769            F896Protocol::CLK_RATES.len()
770        );
771        assert_eq!(
772            F896Protocol::CLK_SRC_VALS.len(),
773            F896Protocol::CLK_SRCS.len()
774        );
775    }
776}