firewire_bebob_protocols/maudio/
special.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2021 Takashi Sakamoto
3
4//! Protocol implementation for M-Audio FireWire 1814 and ProjectMix I/O.
5//!
6//! The module includes structure, enumeration, and trait and its implementation for protocol
7//! defined by M-Audio FireWire 1814 and ProjectMix I/O. The configuration for these models
8//! is write-only, thus the implementaion includes caching mechanism for the configuration.
9//!
10//! DM1000 is used for M-Audio FireWire 1814.
11//!
12//! ## Diagram of internal signal flow for FireWire 1814 and ProjectMix I/O.
13//!
14//! ```text
15//! analog-input-1/2 ---+-------------------------+--------------------------> stream-output-1/2
16//! analog-input-3/4 ---|-+-----------------------|-+------------------------> stream-output-3/4
17//! analog-input-5/6 ---|-|-+---------------------|-|-+----------------------> stream-output-5/6
18//! analog-input-7/8 ---|-|-|-+-------------------|-|-|-+-----------------+
19//! spdif-input-1/2 ----|-|-|-|-+-----------------|-|-|-|-+---------------+--> stream-output-7/8
20//! adat-input-1/2 -----|-|-|-|-|-+---------------|-|-|-|-|-+----------------> stream-output-9/10
21//! adat-input-3/4 -----|-|-|-|-|-|-+-------------|-|-|-|-|-|-+--------------> stream-output-11/12
22//! adat-input-5/6 -----|-|-|-|-|-|-|-+-----------|-|-|-|-|-|-|-+------------> stream-output-13/14
23//! adat-input-7/8 -----|-|-|-|-|-|-|-|-+---------|-|-|-|-|-|-|-|-+----------> stream-output-15/16
24//!                     | | | | | | | | |         | | | | | | | | |
25//!                     | | | | | | | | |         v v v v v v v v v
26//!                     | | | | | | | | |       ++=================++
27//!  stream-input-1/2 --|-|-|-|-|-|-|-|-|-+---> ||      22x2       ||
28//!  stream-input-3/4 --|-|-|-|-|-|-|-|-|-|-+-> ||    aux mixer    || --+
29//!                     | | | | | | | | | | |   ++=================++   |
30//!                     | | | | | | | | | | |                           |
31//!                     v v v v v v v v v v v                     aux-output-1/2
32//!                   ++=====================++                       | | |
33//!                   ||        22x4         || -- mixer-output-1/2 --+-|-|--> analog-output-1/2
34//!                   ||        mixer        || -- mixer-output-3/4 --|-+-|--> analog-output-1/2
35//!                   ++=====================++                       +-+-+--> headphone-1/2
36//!
37//!  stream-input-5/7 -------------------------------------------------------> digital-output-1/2
38//!  stream-input-7/8 -------------------------------------------------------> digital-output-3/4
39//!  stream-input-9/10 ------------------------------------------------------> digital-output-5/6
40//!  stream-input-11/12 -----------------------------------------------------> digital-output-7/8
41//! ```
42//!
43//! The protocol implementation for M-Audio FireWire 1814 was written with firmware version
44//! below:
45//!
46//! ```sh
47//! $ cargo run --bin bco-bootloader-info -- /dev/fw1
48//! protocol:
49//!   version: 1
50//! bootloader:
51//!   timestamp: 2004-03-30T02:59:09+0000
52//!   version: 0.0.0
53//! hardware:
54//!   GUID: 0x007feef8000d6c04
55//!   model ID: 0x000083
56//!   revision: 0.0.1
57//! software:
58//!   timestamp: 2007-07-13T08:04:40+0000
59//!   ID: 0x00000000
60//!   revision: 0.0.0
61//! image:
62//!   base address: 0x20080000
63//!   maximum size: 0x180000
64//! ```
65
66use {super::*, std::ops::Range};
67
68/// The protocol implementation for media clock of FireWire 1814.
69#[derive(Default, Debug)]
70pub struct Fw1814ClkProtocol;
71
72impl MediaClockFrequencyOperation for Fw1814ClkProtocol {
73    const FREQ_LIST: &'static [u32] = &[44100, 48000, 88200, 96000, 176400, 192000];
74
75    fn cache_freq(
76        avc: &BebobAvc,
77        params: &mut MediaClockParameters,
78        timeout_ms: u32,
79    ) -> Result<(), Error> {
80        cache_freq(avc, params, Self::FREQ_LIST, timeout_ms)
81    }
82}
83
84/// The protocol implementation for media clock of ProjectMix I/O.
85#[derive(Default, Debug)]
86pub struct ProjectMixClkProtocol;
87
88impl MediaClockFrequencyOperation for ProjectMixClkProtocol {
89    const FREQ_LIST: &'static [u32] = &[44100, 48000, 88200, 96000];
90
91    fn cache_freq(
92        avc: &BebobAvc,
93        params: &mut MediaClockParameters,
94        timeout_ms: u32,
95    ) -> Result<(), Error> {
96        cache_freq(avc, params, Self::FREQ_LIST, timeout_ms)
97    }
98}
99
100// NOTE: Special models doesn't support any bridgeco extension.
101fn cache_freq(
102    avc: &BebobAvc,
103    params: &mut MediaClockParameters,
104    freq_list: &[u32],
105    timeout_ms: u32,
106) -> Result<(), Error> {
107    let mut op = OutputPlugSignalFormat::new(0);
108    avc.status(&AvcAddr::Unit, &mut op, timeout_ms)?;
109    let fdf = AmdtpFdf::from(&op.0.fdf[..]);
110    freq_list
111        .iter()
112        .position(|&freq| freq == fdf.freq)
113        .ok_or_else(|| {
114            let msg = format!("Unexpected value of FDF: {:?}", fdf);
115            Error::new(FileError::Io, &msg)
116        })
117        .map(|freq_idx| params.freq_idx = freq_idx)
118}
119
120/// AV/C vendor-dependent command for specific LED switch.
121pub struct MaudioSpecialLedSwitch {
122    state: bool,
123    op: VendorDependent,
124}
125
126// NOTE: Unknown OUI.
127const SPECIAL_OUI_A: [u8; 3] = [0x03, 0x00, 0x01];
128
129impl Default for MaudioSpecialLedSwitch {
130    fn default() -> Self {
131        Self {
132            state: Default::default(),
133            op: VendorDependent {
134                company_id: SPECIAL_OUI_A,
135                data: vec![0xff, 0xff],
136            },
137        }
138    }
139}
140
141impl MaudioSpecialLedSwitch {
142    pub fn new(state: bool) -> Self {
143        Self {
144            state,
145            ..Default::default()
146        }
147    }
148}
149
150impl AvcOp for MaudioSpecialLedSwitch {
151    const OPCODE: u8 = VendorDependent::OPCODE;
152}
153
154impl AvcControl for MaudioSpecialLedSwitch {
155    fn build_operands(&mut self, addr: &AvcAddr) -> Result<Vec<u8>, AvcCmdBuildError> {
156        self.op.data[0] = self.state.into();
157        AvcControl::build_operands(&mut self.op, addr)
158    }
159
160    fn parse_operands(&mut self, addr: &AvcAddr, operands: &[u8]) -> Result<(), AvcRespParseError> {
161        AvcControl::parse_operands(&mut self.op, addr, operands)
162    }
163}
164
165/// The protocol implementation for hardware metering.
166#[derive(Default, Debug)]
167pub struct MaudioSpecialMeterProtocol;
168
169const METER_SIZE: usize = 84;
170
171/// Information of hardware metering.
172#[derive(Debug)]
173pub struct MaudioSpecialMeterState {
174    /// Detected levels for analog inputs.
175    pub analog_inputs: [i16; 8],
176    /// Detected levels of S/PDIF inputs.
177    pub spdif_inputs: [i16; 2],
178    /// Detected levels of ADAT inputs.
179    pub adat_inputs: [i16; 8],
180    /// Detected levels of analog outputs.
181    pub analog_outputs: [i16; 4],
182    /// Detected levels of S/PDIF outputs.
183    pub spdif_outputs: [i16; 2],
184    /// Detected levels of ADAT outputs.
185    pub adat_outputs: [i16; 8],
186
187    /// Detected levels of headphone outputs.
188    pub headphone: [i16; 4],
189    /// Detected levels of outputs from auxiliary mixer.
190    pub aux_outputs: [i16; 2],
191    /// Detected state of hardware switch.
192    pub switch: bool,
193    /// Detected states of hardware rotary knobs.
194    pub rotaries: [i16; 3],
195    /// The status of sampling clock synchronization.
196    pub sync_status: bool,
197    cache: [u8; METER_SIZE],
198}
199
200impl Default for MaudioSpecialMeterState {
201    fn default() -> Self {
202        Self {
203            analog_inputs: Default::default(),
204            spdif_inputs: Default::default(),
205            adat_inputs: Default::default(),
206            analog_outputs: Default::default(),
207            spdif_outputs: Default::default(),
208            adat_outputs: Default::default(),
209            headphone: Default::default(),
210            aux_outputs: Default::default(),
211            switch: Default::default(),
212            rotaries: Default::default(),
213            sync_status: Default::default(),
214            cache: [0; METER_SIZE],
215        }
216    }
217}
218
219impl MaudioSpecialMeterProtocol {
220    /// The minimum value of detected level.
221    pub const LEVEL_MIN: i16 = 0;
222    /// The maximum value of detected level.
223    pub const LEVEL_MAX: i16 = i16::MAX;
224    /// The step value of detected level.
225    pub const LEVEL_STEP: i16 = 0x100;
226
227    /// The minimum value of hardware rotary.
228    pub const ROTARY_MIN: i16 = i16::MIN;
229    /// The maximum value of hardware rotary.
230    pub const ROTARY_MAX: i16 = 0;
231    /// The step value of hardware rotary.
232    pub const ROTARY_STEP: i16 = 0x400;
233
234    pub fn cache(
235        req: &FwReq,
236        node: &FwNode,
237        meter: &mut MaudioSpecialMeterState,
238        timeout_ms: u32,
239    ) -> Result<(), Error> {
240        let frame = &mut meter.cache;
241
242        let mut bitmap0 = [0; 4];
243        bitmap0.copy_from_slice(&frame[..4]);
244
245        let mut bitmap1 = [0; 4];
246        bitmap1.copy_from_slice(&frame[(METER_SIZE - 4)..]);
247
248        req.transaction_sync(
249            node,
250            FwTcode::ReadBlockRequest,
251            DM_APPL_METER_OFFSET,
252            frame.len(),
253            frame,
254            timeout_ms,
255        )?;
256
257        let mut doublet = [0; 2];
258
259        meter
260            .analog_inputs
261            .iter_mut()
262            .chain(&mut meter.spdif_inputs)
263            .chain(&mut meter.adat_inputs)
264            .chain(&mut meter.analog_outputs)
265            .chain(&mut meter.spdif_outputs)
266            .chain(&mut meter.adat_outputs)
267            .chain(&mut meter.headphone)
268            .chain(&mut meter.aux_outputs)
269            .enumerate()
270            .for_each(|(i, m)| {
271                let pos = 2 + (1 + i) * 2;
272                doublet.copy_from_slice(&frame[pos..(pos + 2)]);
273                *m = i16::from_be_bytes(doublet);
274            });
275
276        if bitmap0[0] ^ frame[0] > 0 {
277            if frame[0] == 0x01 {
278                meter.switch = !meter.switch;
279            }
280        }
281
282        meter.rotaries.iter_mut().enumerate().for_each(|(i, r)| {
283            let pos = i + 1;
284
285            if bitmap0[pos] ^ frame[pos] > 0 {
286                if frame[pos] == 0x01 {
287                    if *r <= Self::ROTARY_MAX - Self::ROTARY_STEP {
288                        *r += Self::ROTARY_STEP;
289                    } else {
290                        *r = Self::ROTARY_MAX;
291                    }
292                } else if frame[pos] == 0x02 {
293                    if *r >= Self::ROTARY_MIN + Self::ROTARY_STEP {
294                        *r -= Self::ROTARY_STEP;
295                    } else {
296                        *r = Self::ROTARY_MIN;
297                    }
298                }
299            }
300        });
301
302        meter.sync_status = bitmap1[3] ^ frame[METER_SIZE - 1] > 0;
303
304        Ok(())
305    }
306}
307
308const CACHE_SIZE: usize = 160;
309
310// 0x0000 - 0x0008: stream input gains
311// 0x0008 - 0x0010: analog output volumes
312// 0x0010 - 0x0020: analog input gains
313// 0x0020 - 0x0024: spdif input gains
314// 0x0024 - 0x0034: adat input gains
315// 0x0034 - 0x0038: aux output volumes
316// 0x0038 - 0x0040: headphone volumes
317// 0x0040 - 0x0050: analog input balances
318// 0x0050 - 0x0054: spdif input balances
319// 0x0054 - 0x0064: adat input balances
320// 0x0064 - 0x006c: aux stream input gains
321// 0x006c - 0x007c: aux analog input gains
322// 0x007c - 0x0080: aux spdif input gains
323// 0x0080 - 0x0090: aux adat input gains
324// 0x0090 - 0x0094: analog/spdif/adat sources to mixer
325// 0x0094 - 0x0098: stream sources to mixer
326// 0x0098 - 0x009c: source of headphone pair
327// 0x009c - 0x00a0: source of analog output pair
328const STREAM_INPUT_GAIN_RANGE: Range<usize> = Range {
329    start: 0x0000,
330    end: 0x0008,
331};
332const ANALOG_OUTPUT_VOLUME_RANGE: Range<usize> = Range {
333    start: 0x0008,
334    end: 0x0010,
335};
336const ANALOG_INPUT_GAIN_RANGE: Range<usize> = Range {
337    start: 0x0010,
338    end: 0x0020,
339};
340const SPDIF_INPUT_GAIN_RANGE: Range<usize> = Range {
341    start: 0x0020,
342    end: 0x0024,
343};
344const ADAT_INPUT_GAIN_RANGE: Range<usize> = Range {
345    start: 0x0024,
346    end: 0x0034,
347};
348const AUX_OUTPUT_VOLUME_RANGE: Range<usize> = Range {
349    start: 0x0034,
350    end: 0x0038,
351};
352const HEADPHONE_VOLUME_RANGE: Range<usize> = Range {
353    start: 0x0038,
354    end: 0x0040,
355};
356const ANALOG_INPUT_BALANCE_RANGE: Range<usize> = Range {
357    start: 0x0040,
358    end: 0x0050,
359};
360const SPDIF_INPUT_BALANCE_RANGE: Range<usize> = Range {
361    start: 0x0050,
362    end: 0x0054,
363};
364const ADAT_INPUT_BALANCE_RANGE: Range<usize> = Range {
365    start: 0x0054,
366    end: 0x0064,
367};
368const AUX_STREAM_INPUT_GAIN_RANGE: Range<usize> = Range {
369    start: 0x0064,
370    end: 0x006c,
371};
372const AUX_ANALOG_INPUT_GAIN_RANGE: Range<usize> = Range {
373    start: 0x006c,
374    end: 0x007c,
375};
376const AUX_SPDIF_INPUT_GAIN_RANGE: Range<usize> = Range {
377    start: 0x007c,
378    end: 0x0080,
379};
380const AUX_ADAT_INPUT_GAIN_RANGE: Range<usize> = Range {
381    start: 0x0080,
382    end: 0x0090,
383};
384const MIXER_PHYS_SOURCE_RANGE: Range<usize> = Range {
385    start: 0x0090,
386    end: 0x0094,
387};
388const MIXER_STREAM_SOURCE_RANGE: Range<usize> = Range {
389    start: 0x0094,
390    end: 0x0098,
391};
392const HEADPHONE_PAIR_SOURCE_RANGE: Range<usize> = Range {
393    start: 0x0098,
394    end: 0x009c,
395};
396const ANALOG_OUTPUT_PAIR_SOURCE_RANGE: Range<usize> = Range {
397    start: 0x009c,
398    end: 0x00a0,
399};
400
401/// Cache of state.
402#[derive(Debug)]
403pub struct MaudioSpecialStateCache(pub [u8; CACHE_SIZE]);
404
405impl Default for MaudioSpecialStateCache {
406    fn default() -> Self {
407        Self([0; CACHE_SIZE])
408    }
409}
410
411/// Parameters of input.
412#[derive(Debug, Copy, Clone, PartialEq, Eq)]
413pub struct MaudioSpecialInputParameters {
414    /// The gains of stream inputs.
415    pub stream_gains: [i16; 4],
416
417    /// The gains of analog inputs.
418    pub analog_gains: [i16; 8],
419    /// The gains of S/PDIF inputs.
420    pub spdif_gains: [i16; 2],
421    /// The gains of ADAT inputs.
422    pub adat_gains: [i16; 8],
423
424    /// The L/R balance of analog inputs.
425    pub analog_balances: [i16; 8],
426    /// The L/R balance of S/PDIF inputs.
427    pub spdif_balances: [i16; 2],
428    /// The L/R balance of ADAT inputs.
429    pub adat_balances: [i16; 8],
430}
431
432impl Default for MaudioSpecialInputParameters {
433    fn default() -> Self {
434        Self {
435            stream_gains: [MaudioSpecialInputProtocol::GAIN_MAX; 4],
436            analog_gains: [MaudioSpecialInputProtocol::GAIN_MAX; 8],
437            spdif_gains: [MaudioSpecialInputProtocol::GAIN_MAX; 2],
438            adat_gains: [MaudioSpecialInputProtocol::GAIN_MAX; 8],
439            analog_balances: [
440                MaudioSpecialInputProtocol::BALANCE_MIN,
441                MaudioSpecialInputProtocol::BALANCE_MAX,
442                MaudioSpecialInputProtocol::BALANCE_MIN,
443                MaudioSpecialInputProtocol::BALANCE_MAX,
444                MaudioSpecialInputProtocol::BALANCE_MIN,
445                MaudioSpecialInputProtocol::BALANCE_MAX,
446                MaudioSpecialInputProtocol::BALANCE_MIN,
447                MaudioSpecialInputProtocol::BALANCE_MAX,
448            ],
449            spdif_balances: [
450                MaudioSpecialInputProtocol::BALANCE_MIN,
451                MaudioSpecialInputProtocol::BALANCE_MAX,
452            ],
453            adat_balances: [
454                MaudioSpecialInputProtocol::BALANCE_MIN,
455                MaudioSpecialInputProtocol::BALANCE_MAX,
456                MaudioSpecialInputProtocol::BALANCE_MIN,
457                MaudioSpecialInputProtocol::BALANCE_MAX,
458                MaudioSpecialInputProtocol::BALANCE_MIN,
459                MaudioSpecialInputProtocol::BALANCE_MAX,
460                MaudioSpecialInputProtocol::BALANCE_MIN,
461                MaudioSpecialInputProtocol::BALANCE_MAX,
462            ],
463        }
464    }
465}
466
467/// The protocol implementation to operate analog inputs.
468#[derive(Default, Debug)]
469pub struct MaudioSpecialInputProtocol;
470
471impl MaudioSpecialInputProtocol {
472    /// The minimum value of gain.
473    pub const GAIN_MIN: i16 = i16::MIN;
474    /// The maximum value of gain.
475    pub const GAIN_MAX: i16 = 0;
476    /// The step value of gain.
477    pub const GAIN_STEP: i16 = 0x100;
478
479    /// The minimum value of L/R balance.
480    pub const BALANCE_MIN: i16 = i16::MIN;
481    /// The maximum value of L/R balance.
482    pub const BALANCE_MAX: i16 = i16::MAX;
483    /// The step value of L/R balance.
484    pub const BALANCE_STEP: i16 = 0x100;
485}
486
487impl SpecialParametersSerdes<MaudioSpecialInputParameters> for MaudioSpecialInputProtocol {
488    const OFFSET_RANGES: &'static [&'static Range<usize>] = &[
489        &STREAM_INPUT_GAIN_RANGE,
490        &ANALOG_INPUT_GAIN_RANGE,
491        &SPDIF_INPUT_GAIN_RANGE,
492        &ADAT_INPUT_GAIN_RANGE,
493        &ANALOG_INPUT_BALANCE_RANGE,
494        &SPDIF_INPUT_BALANCE_RANGE,
495        &ADAT_INPUT_BALANCE_RANGE,
496    ];
497
498    fn serialize(params: &MaudioSpecialInputParameters, raw: &mut [u8]) {
499        [
500            (&params.stream_gains[..], &STREAM_INPUT_GAIN_RANGE),
501            (&params.analog_gains[..], &ANALOG_INPUT_GAIN_RANGE),
502            (&params.spdif_gains[..], &SPDIF_INPUT_GAIN_RANGE),
503            (&params.adat_gains[..], &ADAT_INPUT_GAIN_RANGE),
504            (&params.analog_balances[..], &ANALOG_INPUT_BALANCE_RANGE),
505            (&params.spdif_balances[..], &SPDIF_INPUT_BALANCE_RANGE),
506            (&params.adat_balances[..], &ADAT_INPUT_BALANCE_RANGE),
507        ]
508        .iter()
509        .for_each(|(gains, range)| {
510            gains.iter().enumerate().for_each(|(i, gain)| {
511                let pos = range.start + i * 2;
512                raw[pos..(pos + 2)].copy_from_slice(&gain.to_be_bytes());
513            })
514        });
515    }
516
517    fn deserialize(params: &mut MaudioSpecialInputParameters, raw: &[u8]) {
518        let mut doublet = [0u8; 2];
519
520        [
521            (&mut params.stream_gains[..], &STREAM_INPUT_GAIN_RANGE),
522            (&mut params.analog_gains[..], &ANALOG_INPUT_GAIN_RANGE),
523            (&mut params.spdif_gains[..], &SPDIF_INPUT_GAIN_RANGE),
524            (&mut params.adat_gains[..], &ADAT_INPUT_GAIN_RANGE),
525            (&mut params.analog_balances[..], &ANALOG_INPUT_BALANCE_RANGE),
526            (&mut params.spdif_balances[..], &SPDIF_INPUT_BALANCE_RANGE),
527            (&mut params.adat_balances[..], &ADAT_INPUT_BALANCE_RANGE),
528        ]
529        .iter_mut()
530        .for_each(|(gains, range)| {
531            gains.iter_mut().enumerate().for_each(|(i, gain)| {
532                let pos = range.start + i * 2;
533                doublet.copy_from_slice(&raw[pos..(pos + 2)]);
534                *gain = i16::from_be_bytes(doublet);
535            })
536        });
537    }
538}
539
540/// Source of analog output.
541#[derive(Debug, Copy, Clone, Eq, PartialEq)]
542pub enum OutputSource {
543    /// The corresponding pair of mixer outputs.
544    MixerOutputPair,
545    /// The pair of auxiliary mixer outputs.
546    AuxOutputPair0,
547}
548
549impl Default for OutputSource {
550    fn default() -> Self {
551        Self::MixerOutputPair
552    }
553}
554
555/// Source of headphone.
556#[derive(Debug, Copy, Clone, Eq, PartialEq)]
557pub enum HeadphoneSource {
558    /// The 1st pair of mixer outputs.
559    MixerOutputPair0,
560    /// The 2nd pair of mixer outputs.
561    MixerOutputPair1,
562    /// The pair of auxiliary mixer outputs.
563    AuxOutputPair0,
564}
565
566impl Default for HeadphoneSource {
567    fn default() -> Self {
568        Self::AuxOutputPair0
569    }
570}
571
572/// Parameters of output.
573#[derive(Debug, Copy, Clone, PartialEq, Eq)]
574pub struct MaudioSpecialOutputParameters {
575    /// The volume of analog outputs.
576    pub analog_volumes: [i16; 4],
577    /// The source for pair of analog outputs.
578    pub analog_pair_sources: [OutputSource; 2],
579    /// The volume of headphone outputs.
580    pub headphone_volumes: [i16; 4],
581    /// The source for pair of headphone outputs.
582    pub headphone_pair_sources: [HeadphoneSource; 2],
583}
584
585impl Default for MaudioSpecialOutputParameters {
586    fn default() -> Self {
587        Self {
588            analog_volumes: [MaudioSpecialOutputProtocol::VOLUME_MAX; 4],
589            analog_pair_sources: [OutputSource::MixerOutputPair; 2],
590            headphone_volumes: [MaudioSpecialOutputProtocol::VOLUME_MAX; 4],
591            headphone_pair_sources: [
592                HeadphoneSource::MixerOutputPair0,
593                HeadphoneSource::MixerOutputPair1,
594            ],
595        }
596    }
597}
598
599/// The protocol implementation for physical output.
600#[derive(Default, Debug)]
601pub struct MaudioSpecialOutputProtocol;
602
603impl MaudioSpecialOutputProtocol {
604    /// The minimum value of volume.
605    pub const VOLUME_MIN: i16 = i16::MIN;
606    /// The maximum value of volume.
607    pub const VOLUME_MAX: i16 = 0;
608    /// The step value of volume.
609    pub const VOLUME_STEP: i16 = 0x100;
610}
611
612impl SpecialParametersSerdes<MaudioSpecialOutputParameters> for MaudioSpecialOutputProtocol {
613    const OFFSET_RANGES: &'static [&'static Range<usize>] = &[
614        &ANALOG_OUTPUT_VOLUME_RANGE,
615        &HEADPHONE_VOLUME_RANGE,
616        &HEADPHONE_PAIR_SOURCE_RANGE,
617        &ANALOG_OUTPUT_PAIR_SOURCE_RANGE,
618    ];
619
620    fn serialize(params: &MaudioSpecialOutputParameters, raw: &mut [u8]) {
621        [
622            (&params.analog_volumes[..], &ANALOG_OUTPUT_VOLUME_RANGE),
623            (&params.headphone_volumes[..], &HEADPHONE_VOLUME_RANGE),
624        ]
625        .iter()
626        .for_each(|(vols, range)| {
627            vols.iter().enumerate().for_each(|(i, vol)| {
628                let pos = range.start + i * 2;
629                raw[pos..(pos + 2)].copy_from_slice(&vol.to_be_bytes());
630            });
631        });
632
633        let mut quadlet = [0; 4];
634        let pos = HEADPHONE_PAIR_SOURCE_RANGE.start;
635        quadlet.copy_from_slice(&raw[pos..(pos + 4)]);
636        let mut val = u32::from_be_bytes(quadlet);
637
638        params
639            .headphone_pair_sources
640            .iter()
641            .enumerate()
642            .for_each(|(i, &src)| {
643                let shift = i * 16;
644                let mask = 0x07;
645                let flag = match src {
646                    HeadphoneSource::MixerOutputPair0 => 0x01,
647                    HeadphoneSource::MixerOutputPair1 => 0x02,
648                    HeadphoneSource::AuxOutputPair0 => 0x04,
649                };
650
651                val &= !(mask << shift);
652                val |= flag << shift;
653            });
654
655        raw[pos..(pos + 4)].copy_from_slice(&val.to_be_bytes());
656
657        let pos = ANALOG_OUTPUT_PAIR_SOURCE_RANGE.start;
658        quadlet.copy_from_slice(&raw[pos..(pos + 4)]);
659        let mut val = u32::from_be_bytes(quadlet);
660
661        params
662            .analog_pair_sources
663            .iter()
664            .enumerate()
665            .for_each(|(i, &src)| {
666                let shift = i;
667                let mask = 0x01;
668                let flag = match src {
669                    OutputSource::MixerOutputPair => 0x00,
670                    OutputSource::AuxOutputPair0 => 0x01,
671                };
672
673                val &= !(mask << shift);
674                val |= flag << shift;
675            });
676
677        raw[pos..(pos + 4)].copy_from_slice(&val.to_be_bytes());
678    }
679
680    fn deserialize(params: &mut MaudioSpecialOutputParameters, raw: &[u8]) {
681        let mut doublet = [0u8; 2];
682
683        [
684            (&mut params.analog_volumes[..], &ANALOG_OUTPUT_VOLUME_RANGE),
685            (&mut params.headphone_volumes[..], &HEADPHONE_VOLUME_RANGE),
686        ]
687        .iter_mut()
688        .for_each(|(vols, range)| {
689            vols.iter_mut().enumerate().for_each(|(i, vol)| {
690                let pos = range.start + i * 2;
691                doublet.copy_from_slice(&raw[pos..(pos + 2)]);
692                *vol = i16::from_be_bytes(doublet);
693            });
694        });
695
696        let mut quadlet = [0u8; 4];
697        let pos = HEADPHONE_PAIR_SOURCE_RANGE.start;
698        quadlet.copy_from_slice(&raw[pos..(pos + 4)]);
699        let val = u32::from_be_bytes(quadlet);
700
701        params
702            .headphone_pair_sources
703            .iter_mut()
704            .enumerate()
705            .for_each(|(i, src)| {
706                let shift = i * 16;
707                let mask = 0x07;
708                let flag = (val >> shift) & mask;
709                *src = match flag {
710                    0x04 => HeadphoneSource::AuxOutputPair0,
711                    0x02 => HeadphoneSource::MixerOutputPair1,
712                    _ => HeadphoneSource::MixerOutputPair0,
713                };
714            });
715
716        let pos = ANALOG_OUTPUT_PAIR_SOURCE_RANGE.start;
717        quadlet.copy_from_slice(&raw[pos..(pos + 4)]);
718        let val = u32::from_be_bytes(quadlet);
719
720        params
721            .analog_pair_sources
722            .iter_mut()
723            .enumerate()
724            .for_each(|(i, src)| {
725                let shift = i;
726                let mask = 0x01;
727                let flag = (val >> shift) & mask;
728                *src = match flag {
729                    0x01 => OutputSource::AuxOutputPair0,
730                    _ => OutputSource::MixerOutputPair,
731                };
732            });
733    }
734}
735
736/// Parameters of aux signal multiplexer.
737#[derive(Debug, Copy, Clone, PartialEq, Eq)]
738pub struct MaudioSpecialAuxParameters {
739    /// The volume of outputs.
740    pub output_volumes: [i16; 2],
741    /// The gain of stream inputs.
742    pub stream_gains: [i16; 4],
743    /// The gain of analog inputs.
744    pub analog_gains: [i16; 8],
745    /// The gain of S/PDIF inputs.
746    pub spdif_gains: [i16; 2],
747    /// The gain of ADAT inputs.
748    pub adat_gains: [i16; 8],
749}
750
751impl Default for MaudioSpecialAuxParameters {
752    fn default() -> Self {
753        Self {
754            output_volumes: [MaudioSpecialAuxProtocol::VOLUME_MAX; 2],
755            stream_gains: [0; 4],
756            analog_gains: [
757                MaudioSpecialAuxProtocol::GAIN_MAX,
758                MaudioSpecialAuxProtocol::GAIN_MAX,
759                MaudioSpecialAuxProtocol::GAIN_MIN,
760                MaudioSpecialAuxProtocol::GAIN_MIN,
761                MaudioSpecialAuxProtocol::GAIN_MIN,
762                MaudioSpecialAuxProtocol::GAIN_MIN,
763                MaudioSpecialAuxProtocol::GAIN_MIN,
764                MaudioSpecialAuxProtocol::GAIN_MIN,
765            ],
766            spdif_gains: [MaudioSpecialAuxProtocol::GAIN_MIN; 2],
767            adat_gains: [MaudioSpecialAuxProtocol::GAIN_MIN; 8],
768        }
769    }
770}
771
772/// The protocol implementation to operate input and output of AUX mixer.
773#[derive(Default, Debug)]
774pub struct MaudioSpecialAuxProtocol;
775
776impl MaudioSpecialAuxProtocol {
777    /// The minimum value of input gain.
778    pub const GAIN_MIN: i16 = i16::MIN;
779    /// The maximum value of input gain.
780    pub const GAIN_MAX: i16 = 0;
781    /// The step value of input gain.
782    pub const GAIN_STEP: i16 = 0x100;
783
784    /// The minimum value of output volume.
785    pub const VOLUME_MIN: i16 = i16::MIN;
786    /// The maximum value of output volume.
787    pub const VOLUME_MAX: i16 = 0;
788    /// The step value of output volume.
789    pub const VOLUME_STEP: i16 = 0x100;
790}
791
792impl SpecialParametersSerdes<MaudioSpecialAuxParameters> for MaudioSpecialAuxProtocol {
793    const OFFSET_RANGES: &'static [&'static Range<usize>] = &[
794        &AUX_OUTPUT_VOLUME_RANGE,
795        &AUX_STREAM_INPUT_GAIN_RANGE,
796        &AUX_ANALOG_INPUT_GAIN_RANGE,
797        &AUX_SPDIF_INPUT_GAIN_RANGE,
798        &AUX_ADAT_INPUT_GAIN_RANGE,
799    ];
800
801    fn serialize(params: &MaudioSpecialAuxParameters, raw: &mut [u8]) {
802        [
803            (&params.output_volumes[..], &AUX_OUTPUT_VOLUME_RANGE),
804            (&params.stream_gains[..], &AUX_STREAM_INPUT_GAIN_RANGE),
805            (&params.analog_gains[..], &AUX_ANALOG_INPUT_GAIN_RANGE),
806            (&params.spdif_gains[..], &AUX_SPDIF_INPUT_GAIN_RANGE),
807            (&params.adat_gains[..], &AUX_ADAT_INPUT_GAIN_RANGE),
808        ]
809        .iter()
810        .for_each(|(levels, range)| {
811            levels.iter().enumerate().for_each(|(i, level)| {
812                let pos = range.start + i * 2;
813                raw[pos..(pos + 2)].copy_from_slice(&level.to_be_bytes());
814            })
815        });
816    }
817
818    fn deserialize(params: &mut MaudioSpecialAuxParameters, raw: &[u8]) {
819        let mut doublet = [0u8; 2];
820
821        [
822            (&mut params.output_volumes[..], &AUX_OUTPUT_VOLUME_RANGE),
823            (&mut params.stream_gains[..], &AUX_STREAM_INPUT_GAIN_RANGE),
824            (&mut params.analog_gains[..], &AUX_ANALOG_INPUT_GAIN_RANGE),
825            (&mut params.spdif_gains[..], &AUX_SPDIF_INPUT_GAIN_RANGE),
826            (&mut params.adat_gains[..], &AUX_ADAT_INPUT_GAIN_RANGE),
827        ]
828        .iter_mut()
829        .for_each(|(levels, range)| {
830            levels.iter_mut().enumerate().for_each(|(i, level)| {
831                let pos = range.start + i * 2;
832                doublet.copy_from_slice(&raw[pos..(pos + 2)]);
833                *level = i16::from_be_bytes(doublet);
834            })
835        });
836    }
837}
838
839/// Parameters of signal multiplexer.
840#[derive(Debug, Copy, Clone, PartialEq, Eq)]
841pub struct MaudioSpecialMixerParameters {
842    /// Enable/Disable the pairs of analog inputs.
843    pub analog_pairs: [[bool; 4]; 2],
844    /// Enable/Disable the pairs of S/PDIF inputs.
845    pub spdif_pairs: [bool; 2],
846    /// Enable/Disable the pairs of ADAT inputs.
847    pub adat_pairs: [[bool; 4]; 2],
848    /// Enable/Disable the pairs of stream inputs.
849    pub stream_pairs: [[bool; 2]; 2],
850}
851
852impl Default for MaudioSpecialMixerParameters {
853    fn default() -> Self {
854        Self {
855            analog_pairs: [[false; 4]; 2],
856            spdif_pairs: [false; 2],
857            adat_pairs: [[false; 4]; 2],
858            stream_pairs: [[true, false], [false, true]],
859        }
860    }
861}
862
863/// The protocol implementation for input and output of mixer.
864#[derive(Default, Debug)]
865pub struct MaudioSpecialMixerProtocol;
866
867impl SpecialParametersSerdes<MaudioSpecialMixerParameters> for MaudioSpecialMixerProtocol {
868    const OFFSET_RANGES: &'static [&'static Range<usize>] =
869        &[&MIXER_PHYS_SOURCE_RANGE, &MIXER_STREAM_SOURCE_RANGE];
870
871    fn serialize(params: &MaudioSpecialMixerParameters, raw: &mut [u8]) {
872        let mut quadlet = [0; 4];
873
874        quadlet.copy_from_slice(&raw[MIXER_PHYS_SOURCE_RANGE]);
875        let mut val = u32::from_be_bytes(quadlet);
876
877        params
878            .analog_pairs
879            .iter()
880            .enumerate()
881            .for_each(|(i, pairs)| {
882                pairs.iter().enumerate().for_each(|(j, &enabled)| {
883                    let flag = 1u32 << (i * 4 + j);
884                    val &= !flag;
885                    if enabled {
886                        val |= flag;
887                    }
888                });
889            });
890
891        params
892            .spdif_pairs
893            .iter()
894            .enumerate()
895            .for_each(|(i, &enabled)| {
896                let flag = 1u32 << (16 + i);
897                val &= !flag;
898                if enabled {
899                    val |= flag;
900                }
901            });
902
903        params.adat_pairs.iter().enumerate().for_each(|(i, pairs)| {
904            pairs.iter().enumerate().for_each(|(j, &enabled)| {
905                let flag = 1u32 << (8 + i * 4 + j);
906                val &= !flag;
907                if enabled {
908                    val |= flag;
909                }
910            });
911        });
912
913        raw[MIXER_PHYS_SOURCE_RANGE].copy_from_slice(&val.to_be_bytes());
914
915        quadlet.copy_from_slice(&raw[MIXER_STREAM_SOURCE_RANGE]);
916        let mut val = u32::from_be_bytes(quadlet);
917
918        params
919            .stream_pairs
920            .iter()
921            .enumerate()
922            .for_each(|(i, pairs)| {
923                pairs.iter().enumerate().for_each(|(j, &enabled)| {
924                    let flag = 1u32 << (j * 2 + i);
925
926                    val &= !flag;
927                    if enabled {
928                        val |= flag;
929                    }
930                });
931            });
932
933        raw[MIXER_STREAM_SOURCE_RANGE].copy_from_slice(&val.to_be_bytes());
934    }
935
936    fn deserialize(params: &mut MaudioSpecialMixerParameters, raw: &[u8]) {
937        let mut quadlet = [0; 4];
938
939        quadlet.copy_from_slice(&raw[MIXER_PHYS_SOURCE_RANGE]);
940        let val = u32::from_be_bytes(quadlet);
941
942        params
943            .analog_pairs
944            .iter_mut()
945            .enumerate()
946            .for_each(|(i, pairs)| {
947                pairs.iter_mut().enumerate().for_each(|(j, enabled)| {
948                    let flag = 1u32 << (i * 4 + j);
949                    *enabled = val & flag > 0;
950                });
951            });
952
953        params
954            .spdif_pairs
955            .iter_mut()
956            .enumerate()
957            .for_each(|(i, enabled)| {
958                let flag = 1u32 << (16 + i);
959                *enabled = val & flag > 0;
960            });
961
962        params
963            .adat_pairs
964            .iter_mut()
965            .enumerate()
966            .for_each(|(i, pairs)| {
967                pairs.iter_mut().enumerate().for_each(|(j, enabled)| {
968                    let flag = 1u32 << (8 + i * 4 + j);
969                    *enabled = val & flag > 0;
970                });
971            });
972
973        quadlet.copy_from_slice(&raw[MIXER_STREAM_SOURCE_RANGE]);
974        let val = u32::from_be_bytes(quadlet);
975
976        params
977            .stream_pairs
978            .iter_mut()
979            .enumerate()
980            .for_each(|(i, pairs)| {
981                pairs.iter_mut().enumerate().for_each(|(j, enabled)| {
982                    let flag = 1u32 << (j * 2 + i);
983                    *enabled = val & flag > 0;
984                });
985            });
986    }
987}
988
989/// Protocol interface for each type of parameters.
990pub trait SpecialParametersSerdes<T: Copy> {
991    /// The set of offset ranges for the type of parameters.
992    const OFFSET_RANGES: &'static [&'static Range<usize>];
993
994    /// Change the content of cache by the given parameters.
995    fn serialize(params: &T, raw: &mut [u8]);
996
997    /// Decode the cache to change the given parameter
998    fn deserialize(params: &mut T, raw: &[u8]);
999}
1000
1001/// The trait for protocol of parameters.
1002pub trait MaudioSpecialParameterProtocol<T: Copy>: SpecialParametersSerdes<T> {
1003    /// Update the hardware for the whole parameters.
1004    fn whole_update(
1005        req: &FwReq,
1006        node: &FwNode,
1007        params: &T,
1008        cache: &mut MaudioSpecialStateCache,
1009        timeout_ms: u32,
1010    ) -> Result<(), Error> {
1011        assert!(Self::OFFSET_RANGES.len() > 0);
1012
1013        Self::serialize(params, &mut cache.0);
1014
1015        let mut peek_iter = Self::OFFSET_RANGES.iter().peekable();
1016        let mut prev_offset = Self::OFFSET_RANGES[0].start;
1017
1018        // NOTE: detect range of continuous offsets or the end entry.
1019        while let Some(curr_range) = peek_iter.next() {
1020            let begin_offset = prev_offset;
1021            let mut next = peek_iter.peek();
1022
1023            if let Some(next_range) = next {
1024                if curr_range.end != next_range.start {
1025                    prev_offset = next_range.start;
1026                    next = None;
1027                }
1028            }
1029
1030            if next.is_none() {
1031                let raw = &mut cache.0[begin_offset..curr_range.end];
1032                if raw.len() == 4 {
1033                    FwTcode::WriteQuadletRequest
1034                } else {
1035                    FwTcode::WriteBlockRequest
1036                };
1037
1038                req.transaction_sync(
1039                    node,
1040                    FwTcode::WriteQuadletRequest,
1041                    DM_APPL_PARAM_OFFSET + begin_offset as u64,
1042                    raw.len(),
1043                    raw,
1044                    timeout_ms,
1045                )?;
1046            }
1047        }
1048
1049        Ok(())
1050    }
1051
1052    /// Update the hardware partially for any change of parameter.
1053    fn partial_update(
1054        req: &FwReq,
1055        node: &FwNode,
1056        params: &T,
1057        cache: &mut MaudioSpecialStateCache,
1058        old: &mut T,
1059        timeout_ms: u32,
1060    ) -> Result<(), Error> {
1061        assert!(Self::OFFSET_RANGES.len() > 0);
1062
1063        let mut new = [0; CACHE_SIZE];
1064        new.copy_from_slice(&cache.0);
1065        Self::serialize(params, &mut new);
1066
1067        Self::OFFSET_RANGES
1068            .iter()
1069            .try_for_each(|range| {
1070                let raw = &mut new[range.start..range.end];
1071
1072                if raw != &cache.0[range.start..range.end] {
1073                    if raw.len() == 4 {
1074                        FwTcode::WriteQuadletRequest
1075                    } else {
1076                        FwTcode::WriteBlockRequest
1077                    };
1078
1079                    req.transaction_sync(
1080                        node,
1081                        FwTcode::WriteQuadletRequest,
1082                        DM_APPL_PARAM_OFFSET + range.start as u64,
1083                        raw.len(),
1084                        raw,
1085                        timeout_ms,
1086                    )
1087                    .map(|_| cache.0[range.start..range.end].copy_from_slice(raw))
1088                } else {
1089                    Ok(())
1090                }
1091            })
1092            .map(|_| *old = *params)
1093    }
1094}
1095
1096impl<O: SpecialParametersSerdes<T>, T: Copy> MaudioSpecialParameterProtocol<T> for O {}
1097
1098#[cfg(test)]
1099mod test {
1100    use super::*;
1101
1102    #[test]
1103    fn offset_ranges() {
1104        let ranges = [
1105            &STREAM_INPUT_GAIN_RANGE,
1106            &ANALOG_OUTPUT_VOLUME_RANGE,
1107            &ANALOG_INPUT_GAIN_RANGE,
1108            &SPDIF_INPUT_GAIN_RANGE,
1109            &ADAT_INPUT_GAIN_RANGE,
1110            &AUX_OUTPUT_VOLUME_RANGE,
1111            &HEADPHONE_VOLUME_RANGE,
1112            &ANALOG_INPUT_BALANCE_RANGE,
1113            &SPDIF_INPUT_BALANCE_RANGE,
1114            &ADAT_INPUT_BALANCE_RANGE,
1115            &AUX_STREAM_INPUT_GAIN_RANGE,
1116            &AUX_ANALOG_INPUT_GAIN_RANGE,
1117            &AUX_SPDIF_INPUT_GAIN_RANGE,
1118            &AUX_ADAT_INPUT_GAIN_RANGE,
1119            &MIXER_PHYS_SOURCE_RANGE,
1120            &MIXER_STREAM_SOURCE_RANGE,
1121            &HEADPHONE_PAIR_SOURCE_RANGE,
1122            &ANALOG_OUTPUT_PAIR_SOURCE_RANGE,
1123        ];
1124
1125        (0..CACHE_SIZE).for_each(|pos| {
1126            let count = ranges.iter().filter(|range| range.contains(&pos)).count();
1127            assert_eq!(count, 1);
1128        });
1129    }
1130
1131    #[test]
1132    fn input_params_serdes() {
1133        let expected = MaudioSpecialInputParameters {
1134            stream_gains: [-2, -1, 0, 1],
1135            analog_gains: [-3, -2, -1, 0, 1, 2, 3, 4],
1136            spdif_gains: [-1, 0],
1137            adat_gains: [-3, -2, -1, 0, 1, 2, 3, 4],
1138            analog_balances: [-3, -2, -1, 0, 1, 2, 3, 4],
1139            spdif_balances: [-1, 0],
1140            adat_balances: [-3, -2, -1, 0, 1, 2, 3, 4],
1141        };
1142        let mut cache = MaudioSpecialStateCache::default();
1143        MaudioSpecialInputProtocol::serialize(&expected, &mut cache.0);
1144
1145        let mut params = MaudioSpecialInputParameters::default();
1146        MaudioSpecialInputProtocol::deserialize(&mut params, &cache.0);
1147
1148        assert_eq!(expected, params);
1149    }
1150
1151    #[test]
1152    fn output_params_serdes() {
1153        let expected = MaudioSpecialOutputParameters {
1154            analog_volumes: [-2, -1, 0, 1],
1155            analog_pair_sources: [OutputSource::MixerOutputPair, OutputSource::AuxOutputPair0],
1156            headphone_volumes: [-1, 0, 1, 2],
1157            headphone_pair_sources: [
1158                HeadphoneSource::AuxOutputPair0,
1159                HeadphoneSource::MixerOutputPair0,
1160            ],
1161        };
1162        let mut cache = MaudioSpecialStateCache::default();
1163        MaudioSpecialOutputProtocol::serialize(&expected, &mut cache.0);
1164
1165        let mut params = MaudioSpecialOutputParameters::default();
1166        MaudioSpecialOutputProtocol::deserialize(&mut params, &cache.0);
1167
1168        assert_eq!(expected, params);
1169    }
1170
1171    #[test]
1172    fn aux_params_serdes() {
1173        let expected = MaudioSpecialAuxParameters {
1174            output_volumes: [0, 1],
1175            stream_gains: [-3, -2, -1, 0],
1176            analog_gains: [-3, -2, -1, 0, 1, 2, 3, 4],
1177            spdif_gains: [-1, 0],
1178            adat_gains: [-3, -2, -1, 0, 1, 2, 3, 4],
1179        };
1180        let mut cache = MaudioSpecialStateCache::default();
1181        MaudioSpecialAuxProtocol::serialize(&expected, &mut cache.0);
1182
1183        let mut params = MaudioSpecialAuxParameters::default();
1184        MaudioSpecialAuxProtocol::deserialize(&mut params, &cache.0);
1185
1186        assert_eq!(expected, params);
1187    }
1188
1189    #[test]
1190    fn mixer_params_serdes() {
1191        let expected = MaudioSpecialMixerParameters {
1192            analog_pairs: [[false, true, false, true], [true, false, true, false]],
1193            spdif_pairs: [true, false],
1194            adat_pairs: [[false, true, false, true], [true, false, true, false]],
1195            stream_pairs: [[true, false], [false, true]],
1196        };
1197        let mut cache = MaudioSpecialStateCache::default();
1198        MaudioSpecialMixerProtocol::serialize(&expected, &mut cache.0);
1199
1200        let mut params = MaudioSpecialMixerParameters::default();
1201        MaudioSpecialMixerProtocol::deserialize(&mut params, &cache.0);
1202
1203        assert_eq!(expected, params);
1204    }
1205}