firewire_bebob_protocols/yamaha_terratec.rs
1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2021 Takashi Sakamoto
3
4//! Protocol implementation for Yamaha Go and Terratec Phase 24 FW series.
5//!
6//! The module includes structure, enumeration, and trait and its implementation for protocol
7//! defined by Yamaha and Terratec for Go and 24 FW series.
8//!
9//! DM1000E is used for Yamaha GO 44 and GO 46.
10//!
11//! ## Diagram of internal signal flow
12//!
13//! ```text
14//! analog-input-1/2 --+----------------------------------------+-----> stream-output-1/2
15//! digital-input-1/2 --|-+--------------------------------------|-+---> stream-output-3/4
16//! | | | |
17//! | | ++=======++ | |
18//! +-|----> || || | |
19//! +----> || || | |
20//! || 6 x 2 || | |
21//! stream-input-1/2 ---+------> || mixer ||--> mixer-output-1/2 | |
22//! stream-input-3/4 ---|-+----> || || | | |
23//! stream-input-5/6 ---|-|-+--> || || | | |
24//! | | | ++=======++ | | |
25//! +-|-|--------------------------|---------|-|--->
26//! | +-|--------------------------|---------|-|--->
27//! | | +--------------------------|---------|-|---> analog-output-1/2
28//! | | | +---------|-|---> (one source only)
29//! | | | | +-|--->
30//! | | | | | +--->
31//! | | | | | |
32//! +-|-|--------------------------|---------|-|--->
33//! | +-|--------------------------|---------|-|--->
34//! | | +--------------------------|---------|-|---> analog-output-3/4
35//! | | | +---------|-|---> (one source only)
36//! | | | | +-|--->
37//! | | | | | +--->
38//! | | | | | |
39//! +-|-|--------------------------|---------|-|--->
40//! +-|--------------------------|---------|-|--->
41//! +--------------------------|---------|-|---> digital-output-1/2
42//! +---------|-|---> (one source only)
43//! +-|--->
44//! +--->
45//! ```
46//!
47//! The protocol implementation for Yamaha GO 44 was written with firmware version below:
48//!
49//! ```sh
50//! $ cargo run --bin bco-bootloader-info -- /dev/fw1
51//! protocol:
52//! version: 1
53//! bootloader:
54//! timestamp: 2005-12-20T10:10:04+0000
55//! version: 0.0.0
56//! hardware:
57//! GUID: 0x0002e24700a0de00
58//! model ID: 0x00000b
59//! revision: 0.0.1
60//! software:
61//! timestamp: 2006-04-20T10:57:53+0000
62//! ID: 0x0010000b
63//! revision: 1.29.3359
64//! image:
65//! base address: 0x20080000
66//! maximum size: 0x180000
67//! ```
68//!
69//! The protocol implementation for Yamaha GO 46 was written with firmware version below:
70//!
71//! ```sh
72//! $ cargo run --bin bco-bootloader-info -- /dev/fw1
73//! protocol:
74//! version: 1
75//! bootloader:
76//! timestamp: 2005-12-20T10:10:14+0000
77//! version: 0.0.0
78//! hardware:
79//! GUID: 0x000283e700a0de00
80//! model ID: 0x00000c
81//! revision: 0.0.1
82//! software:
83//! timestamp: 2006-01-26T02:31:32+0000
84//! ID: 0x0010000c
85//! revision: 1.34.3359
86//! image:
87//! base address: 0x20080000
88//! maximum size: 0x180000
89//! ```
90//!
91//! The protocol implementation for Terratec Phase X24 was written with firmware version below:
92//!
93//! ```sh
94//! $ cargo run --bin bco-bootloader-info -- /dev/fw1
95//! protocol:
96//! version: 1
97//! bootloader:
98//! timestamp: 2005-07-29T02:05:14+0000
99//! version: 0.0.0
100//! hardware:
101//! GUID: 0x0062c9c7000aac07
102//! model ID: 0x000007
103//! revision: 0.0.1
104//! software:
105//! timestamp: 2005-07-25T01:56:53+0000
106//! ID: 0x00000007
107//! revision: 1.32.3359
108//! image:
109//! base address: 0x20080000
110//! maximum size: 0x180000
111//! ```
112
113use super::*;
114
115/// The protocol implementation of media and sampling clock for Yamaha Go 44/46 and PHASE 24/X24 FW;
116#[derive(Default, Debug)]
117pub struct GoPhase24ClkProtocol;
118
119impl MediaClockFrequencyOperation for GoPhase24ClkProtocol {
120 const FREQ_LIST: &'static [u32] = &[44100, 48000, 88200, 96000, 192000];
121}
122
123const CLK_SRC_FB_ID: u8 = 0x04;
124
125impl SamplingClockSourceOperation for GoPhase24ClkProtocol {
126 // NOTE: these destination and source can not be connected actually.
127 const DST: SignalAddr = SignalAddr::Subunit(SignalSubunitAddr {
128 subunit: MUSIC_SUBUNIT_0,
129 plug_id: 0x04,
130 });
131
132 const SRC_LIST: &'static [SignalAddr] = &[
133 // Internal.
134 SignalAddr::Subunit(SignalSubunitAddr {
135 subunit: MUSIC_SUBUNIT_0,
136 plug_id: 0x03,
137 }),
138 // S/PDIF input.
139 SignalAddr::Unit(SignalUnitAddr::Ext(0x01)),
140 ];
141
142 fn cache_src(
143 avc: &BebobAvc,
144 params: &mut SamplingClockParameters,
145 timeout_ms: u32,
146 ) -> Result<(), Error> {
147 let mut op = AudioSelector::new(CLK_SRC_FB_ID, CtlAttr::Current, 0xff);
148 avc.status(&AUDIO_SUBUNIT_0_ADDR, &mut op, timeout_ms)
149 .map(|_| params.src_idx = op.input_plug_id as usize)
150 }
151
152 fn update_src(
153 avc: &BebobAvc,
154 params: &SamplingClockParameters,
155 old: &mut SamplingClockParameters,
156 timeout_ms: u32,
157 ) -> Result<(), Error> {
158 let mut op = AudioSelector::new(CLK_SRC_FB_ID, CtlAttr::Current, params.src_idx as u8);
159 avc.control(&AUDIO_SUBUNIT_0_ADDR, &mut op, timeout_ms)
160 .map(|_| *old = *params)
161 }
162}
163
164/// The protocol implementation of physical input for coaxial models.
165pub struct GoPhase24CoaxPhysInputProtocol;
166
167const INPUT_NOMINAL_LEVEL_FB_ID: u8 = 0x02;
168
169const INPUT_NOMINAL_LEVELS: [i16; 3] = [0xf400u16 as i16, 0xfd00u16 as i16, 0x0000u16 as i16];
170
171impl AvcSelectorOperation for GoPhase24CoaxPhysInputProtocol {
172 // Unused.
173 const FUNC_BLOCK_ID_LIST: &'static [u8] = &[0x00];
174 const INPUT_PLUG_ID_LIST: &'static [u8] = &[0x00, 0x01, 0x02];
175
176 fn cache_selectors(
177 avc: &BebobAvc,
178 params: &mut AvcSelectorParameters,
179 timeout_ms: u32,
180 ) -> Result<(), Error> {
181 assert_eq!(params.selectors.len(), 1);
182
183 let mut op = AudioFeature::new(
184 INPUT_NOMINAL_LEVEL_FB_ID,
185 CtlAttr::Current,
186 AudioCh::Master,
187 FeatureCtl::Volume(VolumeData::new(1)),
188 );
189 avc.status(&AUDIO_SUBUNIT_0_ADDR, &mut op, timeout_ms)?;
190 if let FeatureCtl::Volume(data) = op.ctl {
191 INPUT_NOMINAL_LEVELS
192 .iter()
193 .position(|l| *l == data.0[0])
194 .ok_or_else(|| {
195 let msg = format!(
196 "Unexpected value for value of nominal level: 0x{:04x}",
197 data.0[0]
198 );
199 Error::new(FileError::Io, &msg)
200 })
201 .map(|pos| params.selectors[0] = pos)
202 } else {
203 Ok(())
204 }
205 }
206
207 fn update_selectors(
208 avc: &BebobAvc,
209 params: &AvcSelectorParameters,
210 old: &mut AvcSelectorParameters,
211 timeout_ms: u32,
212 ) -> Result<(), Error> {
213 assert_eq!(params.selectors.len(), 1);
214 assert_eq!(old.selectors.len(), 1);
215
216 if old.selectors[0] != params.selectors[0] {
217 let val = INPUT_NOMINAL_LEVELS
218 .iter()
219 .nth(old.selectors[0])
220 .ok_or_else(|| {
221 let msg = format!(
222 "Invalid argument for index of nominal level: {}",
223 old.selectors[0]
224 );
225 Error::new(FileError::Inval, &msg)
226 })
227 .copied()?;
228 let mut op = AudioFeature::new(
229 INPUT_NOMINAL_LEVEL_FB_ID,
230 CtlAttr::Current,
231 AudioCh::Master,
232 FeatureCtl::Volume(VolumeData(vec![val])),
233 );
234 avc.control(&AUDIO_SUBUNIT_0_ADDR, &mut op, timeout_ms)
235 .map(|_| {
236 old.selectors[0] = params.selectors[0];
237 })
238 } else {
239 Ok(())
240 }
241 }
242}
243
244/// The protocol implementation of physical output for coaxial models.
245pub struct GoPhase24CoaxPhysOutputProtocol;
246
247impl AvcSelectorOperation for GoPhase24CoaxPhysOutputProtocol {
248 const FUNC_BLOCK_ID_LIST: &'static [u8] = &[
249 0x01, // analog-output-1/2
250 0x03, // digital-output-1/2
251 ];
252 const INPUT_PLUG_ID_LIST: &'static [u8] = &[
253 0x00, // stream-input-1/2
254 0x01, // stream-input-3/4
255 0x02, // analog-input-1/2
256 0x03, // digital-input-1/2
257 0x04, // mixer-output-1/2
258 0x05, // stream-input-5/6
259 ];
260}
261/// The protocol implementation of physical output for optical models.
262#[derive(Default, Debug)]
263pub struct GoPhase24OptPhysOutputProtocol;
264
265impl AvcAudioFeatureSpecification for GoPhase24OptPhysOutputProtocol {
266 const ENTRIES: &'static [(u8, AudioCh)] = &[
267 (0x01, AudioCh::Each(0)), // analog-output-1
268 (0x01, AudioCh::Each(1)), // analog-output-2
269 (0x01, AudioCh::Each(2)), // analog-output-3
270 (0x01, AudioCh::Each(3)), // analog-output-4
271 ];
272}
273
274impl AvcLevelOperation for GoPhase24OptPhysOutputProtocol {}
275
276impl AvcMuteOperation for GoPhase24OptPhysOutputProtocol {}
277
278impl AvcSelectorOperation for GoPhase24OptPhysOutputProtocol {
279 const FUNC_BLOCK_ID_LIST: &'static [u8] = &[
280 0x01, // analog-output-1/2
281 0x02, // analog-output-3/4
282 0x03, // digital-output-1/2
283 ];
284 const INPUT_PLUG_ID_LIST: &'static [u8] = &[
285 0x00, // stream-input-1/2
286 0x01, // stream-input-3/4
287 0x02, // analog-input-1/2
288 0x03, // digital-input-1/2
289 0x04, // mixer-output-1/2
290 0x05, // stream-input-5/6
291 ];
292}
293
294/// The protocol implementation of mixer source gain for coaxial model.
295pub struct GoPhase24CoaxHeadphoneProtocol;
296
297impl AvcSelectorOperation for GoPhase24CoaxHeadphoneProtocol {
298 const FUNC_BLOCK_ID_LIST: &'static [u8] = &[0x02];
299 const INPUT_PLUG_ID_LIST: &'static [u8] = &[
300 0x00, // stream-input-1/2
301 0x01, // stream-input-3/4
302 0x02, // analog-input-1/2
303 0x03, // digital-input-1/2
304 0x04, // mixer-output-1/2
305 0x05, // stream-input-5/6
306 ];
307}
308
309/// The protocol implementation of mixer source gain.
310#[derive(Default, Debug)]
311pub struct GoPhase24MixerSourceProtocol;
312
313impl AvcAudioFeatureSpecification for GoPhase24MixerSourceProtocol {
314 const ENTRIES: &'static [(u8, AudioCh)] = &[
315 (0x06, AudioCh::Each(0)), // analog-input-1/2
316 (0x06, AudioCh::Each(1)), // analog-input-1/2
317 (0x07, AudioCh::Each(0)), // digital-input-1/2
318 (0x07, AudioCh::Each(1)), // digital-input-1/2
319 (0x03, AudioCh::Each(0)), // stream-input-1/2
320 (0x03, AudioCh::Each(1)), // stream-input-1/2
321 (0x04, AudioCh::Each(0)), // stream-input-3/4
322 (0x04, AudioCh::Each(1)), // stream-input-3/4
323 (0x05, AudioCh::Each(0)), // stream-input-5/6
324 (0x05, AudioCh::Each(1)), // stream-input-5/6
325 ];
326}
327
328impl AvcLevelOperation for GoPhase24MixerSourceProtocol {}
329
330impl AvcMuteOperation for GoPhase24MixerSourceProtocol {}
331
332/// The protocol implementation of mixer output volume for coaxial models.
333#[derive(Default, Debug)]
334pub struct GoPhase24CoaxMixerOutputProtocol;
335
336impl AvcAudioFeatureSpecification for GoPhase24CoaxMixerOutputProtocol {
337 const ENTRIES: &'static [(u8, AudioCh)] = &[(0x01, AudioCh::Each(0)), (0x01, AudioCh::Each(1))];
338}
339
340impl AvcLevelOperation for GoPhase24CoaxMixerOutputProtocol {}
341
342impl AvcMuteOperation for GoPhase24CoaxMixerOutputProtocol {}
343
344/// The protocol implementation of mixer output volume for optical models.
345#[derive(Default, Debug)]
346pub struct GoPhase24OptMixerOutputProtocol;
347
348impl AvcAudioFeatureSpecification for GoPhase24OptMixerOutputProtocol {
349 const ENTRIES: &'static [(u8, AudioCh)] = &[(0x02, AudioCh::Each(0)), (0x02, AudioCh::Each(1))];
350}
351
352impl AvcLevelOperation for GoPhase24OptMixerOutputProtocol {}
353
354impl AvcMuteOperation for GoPhase24OptMixerOutputProtocol {}