1#![doc = include_str!("../README.md")]
5
6pub mod bridgeco;
7
8pub mod apogee;
9pub mod behringer;
10pub mod digidesign;
11pub mod esi;
12pub mod focusrite;
13pub mod icon;
14pub mod maudio;
15pub mod presonus;
16pub mod roland;
17pub mod stanton;
18pub mod terratec;
19pub mod yamaha_terratec;
20
21use {
22 self::bridgeco::{ExtendedStreamFormatSingle, *},
23 glib::{Error, FileError, IsA},
24 hinawa::{
25 prelude::{FwFcpExt, FwFcpExtManual, FwReqExtManual},
26 FwFcp, FwNode, FwReq, FwTcode,
27 },
28 ta1394_avc_audio::{amdtp::*, *},
29 ta1394_avc_ccm::*,
30 ta1394_avc_general::{general::*, *},
31 ta1394_avc_stream_format::*,
32};
33
34const DM_APPL_OFFSET: u64 = 0xffc700000000;
36const DM_APPL_METER_OFFSET: u64 = DM_APPL_OFFSET + 0x00600000;
37const DM_APPL_PARAM_OFFSET: u64 = DM_APPL_OFFSET + 0x00700000;
38const DM_BCO_OFFSET: u64 = 0xffffc8000000;
39const DM_BCO_BOOTLOADER_INFO_OFFSET: u64 = DM_BCO_OFFSET + 0x00020000;
40
41#[derive(Default, Debug)]
46pub struct BebobAvc(FwFcp);
47
48impl Ta1394Avc<Error> for BebobAvc {
49 fn transaction(&self, command_frame: &[u8], timeout_ms: u32) -> Result<Vec<u8>, Error> {
50 let mut resp = vec![0; Self::FRAME_SIZE];
51 self.0
52 .avc_transaction(&command_frame, &mut resp, timeout_ms)
53 .map(|len| {
54 resp.truncate(len);
55 resp
56 })
57 }
58
59 fn control<O: AvcOp + AvcControl>(
60 &self,
61 addr: &AvcAddr,
62 op: &mut O,
63 timeout_ms: u32,
64 ) -> Result<(), Ta1394AvcError<Error>> {
65 let operands =
66 AvcControl::build_operands(op, addr).map_err(|err| Ta1394AvcError::CmdBuild(err))?;
67 let command_frame =
68 Self::compose_command_frame(AvcCmdType::Control, addr, O::OPCODE, &operands)?;
69 let response_frame = self
70 .transaction(&command_frame, timeout_ms)
71 .map_err(|cause| Ta1394AvcError::CommunicationFailure(cause))?;
72 Self::detect_response_operands(&response_frame, addr, O::OPCODE)
73 .and_then(|(rcode, operands)| {
74 let expected = match O::OPCODE {
75 InputPlugSignalFormat::OPCODE
76 | OutputPlugSignalFormat::OPCODE
77 | SignalSource::OPCODE => {
78 rcode == AvcRespCode::Accepted || rcode == AvcRespCode::Reserved(0x00)
80 }
81 _ => rcode == AvcRespCode::Accepted,
82 };
83 if !expected {
84 Err(AvcRespParseError::UnexpectedStatus)
85 } else {
86 AvcControl::parse_operands(op, addr, &operands)
87 }
88 })
89 .map_err(|err| Ta1394AvcError::RespParse(err))
90 }
91}
92
93impl BebobAvc {
94 pub fn bind(&self, node: &impl IsA<FwNode>) -> Result<(), Error> {
95 self.0.bind(node)
96 }
97
98 pub fn control<O: AvcOp + AvcControl>(
99 &self,
100 addr: &AvcAddr,
101 op: &mut O,
102 timeout_ms: u32,
103 ) -> Result<(), Error> {
104 Ta1394Avc::<Error>::control(self, addr, op, timeout_ms).map_err(|err| from_avc_err(err))
105 }
106
107 pub fn status<O: AvcOp + AvcStatus>(
108 &self,
109 addr: &AvcAddr,
110 op: &mut O,
111 timeout_ms: u32,
112 ) -> Result<(), Error> {
113 Ta1394Avc::<Error>::status(self, addr, op, timeout_ms).map_err(|err| from_avc_err(err))
114 }
115}
116
117fn from_avc_err(err: Ta1394AvcError<Error>) -> Error {
118 match err {
119 Ta1394AvcError::CmdBuild(cause) => Error::new(FileError::Inval, &cause.to_string()),
120 Ta1394AvcError::CommunicationFailure(cause) => cause,
121 Ta1394AvcError::RespParse(cause) => Error::new(FileError::Io, &cause.to_string()),
122 }
123}
124
125#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
127pub struct MediaClockParameters {
128 pub freq_idx: usize,
130}
131
132pub trait MediaClockFrequencyOperation {
134 const FREQ_LIST: &'static [u32];
136
137 fn cache_freq(
139 avc: &BebobAvc,
140 params: &mut MediaClockParameters,
141 timeout_ms: u32,
142 ) -> Result<(), Error> {
143 let plug_addr =
144 BcoPlugAddr::new_for_unit(BcoPlugDirection::Output, BcoPlugAddrUnitType::Isoc, 0);
145 let mut op = ExtendedStreamFormatSingle::new(&plug_addr);
146
147 avc.status(&AvcAddr::Unit, &mut op, timeout_ms)?;
148
149 op.stream_format
150 .as_bco_compound_am824_stream()
151 .ok_or_else(|| {
152 let label = "Bco Compound AM824 stream is not available for the unit";
153 Error::new(FileError::Nxio, &label)
154 })
155 .and_then(|format| {
156 Self::FREQ_LIST
157 .iter()
158 .position(|&r| r == format.freq)
159 .ok_or_else(|| {
160 let msg = format!("Unexpected entry for source of clock: {}", format.freq);
161 Error::new(FileError::Io, &msg)
162 })
163 })
164 .map(|freq_idx| params.freq_idx = freq_idx)
165 }
166
167 fn update_freq(
170 avc: &BebobAvc,
171 params: &MediaClockParameters,
172 old: &mut MediaClockParameters,
173 timeout_ms: u32,
174 ) -> Result<(), Error> {
175 let fdf = Self::FREQ_LIST
176 .iter()
177 .nth(params.freq_idx)
178 .ok_or_else(|| {
179 let msg = format!(
180 "Invalid argument for index of frequency: {}",
181 params.freq_idx
182 );
183 Error::new(FileError::Inval, &msg)
184 })
185 .map(|&freq| AmdtpFdf::new(AmdtpEventType::Am824, false, freq))?;
186
187 let mut op = InputPlugSignalFormat(PlugSignalFormat {
188 plug_id: 0,
189 fmt: FMT_IS_AMDTP,
190 fdf: fdf.into(),
191 });
192 avc.control(&AvcAddr::Unit, &mut op, timeout_ms)?;
193
194 let mut op = OutputPlugSignalFormat(PlugSignalFormat {
195 plug_id: 0,
196 fmt: FMT_IS_AMDTP,
197 fdf: fdf.into(),
198 });
199 avc.control(&AvcAddr::Unit, &mut op, timeout_ms)?;
200
201 *old = *params;
202
203 Ok(())
204 }
205}
206
207#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
209pub struct SamplingClockParameters {
210 pub src_idx: usize,
212}
213
214pub trait SamplingClockSourceOperation {
216 const DST: SignalAddr;
223 const SRC_LIST: &'static [SignalAddr];
225
226 fn cache_src(
228 avc: &BebobAvc,
229 params: &mut SamplingClockParameters,
230 timeout_ms: u32,
231 ) -> Result<(), Error> {
232 let mut op = SignalSource::new(&Self::DST);
233
234 avc.status(&AvcAddr::Unit, &mut op, timeout_ms)?;
235
236 Self::SRC_LIST
237 .iter()
238 .position(|&s| s == op.src)
239 .ok_or_else(|| {
240 let label = "Unexpected entry for source of clock";
241 Error::new(FileError::Io, &label)
242 })
243 .map(|src_idx| params.src_idx = src_idx)
244 }
245
246 fn update_src(
249 avc: &BebobAvc,
250 params: &SamplingClockParameters,
251 old: &mut SamplingClockParameters,
252 timeout_ms: u32,
253 ) -> Result<(), Error> {
254 let src = Self::SRC_LIST
255 .iter()
256 .nth(params.src_idx)
257 .ok_or_else(|| {
258 let label = "Invalid value for source of clock";
259 Error::new(FileError::Inval, &label)
260 })
261 .copied()?;
262
263 let mut op = SignalSource::new(&Self::DST);
264 op.src = src;
265
266 avc.control(&AvcAddr::Unit, &mut op, timeout_ms)
267 .map(|_| *old = *params)
268 }
269}
270
271pub trait AvcAudioFeatureSpecification {
273 const ENTRIES: &'static [(u8, AudioCh)];
275}
276
277#[derive(Debug, Clone, PartialEq, Eq)]
280pub struct AvcLevelParameters {
281 pub levels: Vec<i16>,
283}
284
285pub trait AvcLevelOperation: AvcAudioFeatureSpecification {
287 const LEVEL_MIN: i16 = VolumeData::VALUE_NEG_INFINITY;
289 const LEVEL_MAX: i16 = VolumeData::VALUE_ZERO;
291 const LEVEL_STEP: i16 = 0x100;
293
294 fn create_level_parameters() -> AvcLevelParameters {
296 AvcLevelParameters {
297 levels: vec![Default::default(); Self::ENTRIES.len()],
298 }
299 }
300
301 fn cache_levels(
303 avc: &BebobAvc,
304 params: &mut AvcLevelParameters,
305 timeout_ms: u32,
306 ) -> Result<(), Error> {
307 assert_eq!(params.levels.len(), Self::ENTRIES.len());
308
309 params
310 .levels
311 .iter_mut()
312 .zip(Self::ENTRIES)
313 .try_for_each(|(level, entry)| {
314 let &(func_block_id, audio_ch) = entry;
315 let mut op = AudioFeature::new(
316 func_block_id,
317 CtlAttr::Current,
318 audio_ch,
319 FeatureCtl::Volume(VolumeData::new(1)),
320 );
321 avc.status(&AUDIO_SUBUNIT_0_ADDR, &mut op, timeout_ms)
322 .map(|_| {
323 if let FeatureCtl::Volume(data) = op.ctl {
324 *level = data.0[0]
325 }
326 })
327 })
328 }
329
330 fn update_levels(
332 avc: &BebobAvc,
333 params: &AvcLevelParameters,
334 old: &mut AvcLevelParameters,
335 timeout_ms: u32,
336 ) -> Result<(), Error> {
337 assert_eq!(params.levels.len(), Self::ENTRIES.len());
338 assert_eq!(old.levels.len(), Self::ENTRIES.len());
339
340 old.levels
341 .iter_mut()
342 .zip(params.levels.iter())
343 .zip(Self::ENTRIES)
344 .filter(|((old, new), _)| !new.eq(old))
345 .try_for_each(|((old, new), entry)| {
346 let &(func_block_id, audio_ch) = entry;
347 let mut op = AudioFeature::new(
348 func_block_id,
349 CtlAttr::Current,
350 audio_ch,
351 FeatureCtl::Volume(VolumeData(vec![*new])),
352 );
353 avc.control(&AUDIO_SUBUNIT_0_ADDR, &mut op, timeout_ms)
354 .map(|_| *old = *new)
355 })
356 }
357}
358
359#[derive(Debug, Clone, PartialEq, Eq)]
362pub struct AvcLrBalanceParameters {
363 pub balances: Vec<i16>,
365}
366
367pub trait AvcLrBalanceOperation: AvcAudioFeatureSpecification {
369 const BALANCE_MIN: i16 = LrBalanceData::VALUE_LEFT_NEG_INFINITY;
371 const BALANCE_MAX: i16 = LrBalanceData::VALUE_LEFT_MAX;
373 const BALANCE_STEP: i16 = 0x80;
375
376 fn create_lr_balance_parameters() -> AvcLrBalanceParameters {
378 AvcLrBalanceParameters {
379 balances: vec![Default::default(); Self::ENTRIES.len()],
380 }
381 }
382
383 fn cache_lr_balances(
385 avc: &BebobAvc,
386 params: &mut AvcLrBalanceParameters,
387 timeout_ms: u32,
388 ) -> Result<(), Error> {
389 assert_eq!(params.balances.len(), Self::ENTRIES.len());
390
391 params
392 .balances
393 .iter_mut()
394 .zip(Self::ENTRIES)
395 .try_for_each(|(balance, entry)| {
396 let &(func_block_id, audio_ch) = entry;
397 let mut op = AudioFeature::new(
398 func_block_id,
399 CtlAttr::Current,
400 audio_ch,
401 FeatureCtl::LrBalance(Default::default()),
402 );
403 avc.status(&AUDIO_SUBUNIT_0_ADDR, &mut op, timeout_ms)
404 .map(|_| {
405 if let FeatureCtl::LrBalance(data) = op.ctl {
406 *balance = data.0;
407 }
408 })
409 })
410 }
411
412 fn update_lr_balances(
414 avc: &BebobAvc,
415 params: &AvcLrBalanceParameters,
416 old: &mut AvcLrBalanceParameters,
417 timeout_ms: u32,
418 ) -> Result<(), Error> {
419 assert_eq!(params.balances.len(), Self::ENTRIES.len());
420 assert_eq!(old.balances.len(), Self::ENTRIES.len());
421
422 old.balances
423 .iter_mut()
424 .zip(params.balances.iter())
425 .zip(Self::ENTRIES)
426 .filter(|((o, n), _)| !o.eq(n))
427 .try_for_each(|((old, &new), entry)| {
428 let &(func_block_id, audio_ch) = entry;
429 let mut op = AudioFeature::new(
430 func_block_id,
431 CtlAttr::Current,
432 audio_ch,
433 FeatureCtl::LrBalance(LrBalanceData(new)),
434 );
435 avc.control(&AUDIO_SUBUNIT_0_ADDR, &mut op, timeout_ms)
436 .map(|_| *old = new)
437 })
438 }
439}
440
441#[derive(Debug, Clone, PartialEq, Eq)]
444pub struct AvcMuteParameters {
445 pub mutes: Vec<bool>,
447}
448
449pub trait AvcMuteOperation: AvcAudioFeatureSpecification {
451 fn create_mute_parameters() -> AvcMuteParameters {
453 AvcMuteParameters {
454 mutes: vec![Default::default(); Self::ENTRIES.len()],
455 }
456 }
457
458 fn cache_mutes(
460 avc: &BebobAvc,
461 params: &mut AvcMuteParameters,
462 timeout_ms: u32,
463 ) -> Result<(), Error> {
464 assert_eq!(params.mutes.len(), Self::ENTRIES.len());
465
466 params
467 .mutes
468 .iter_mut()
469 .zip(Self::ENTRIES)
470 .try_for_each(|(mute, entry)| {
471 let &(func_block_id, audio_ch) = entry;
472
473 let mut op = AudioFeature::new(
474 func_block_id,
475 CtlAttr::Current,
476 audio_ch,
477 FeatureCtl::Mute(vec![false]),
478 );
479 avc.status(&AUDIO_SUBUNIT_0_ADDR, &mut op, timeout_ms)
480 .map(|_| {
481 if let FeatureCtl::Mute(data) = op.ctl {
482 *mute = data[0];
483 }
484 })
485 })
486 }
487
488 fn update_mutes(
490 avc: &BebobAvc,
491 params: &AvcMuteParameters,
492 old: &mut AvcMuteParameters,
493 timeout_ms: u32,
494 ) -> Result<(), Error> {
495 assert_eq!(params.mutes.len(), Self::ENTRIES.len());
496 assert_eq!(old.mutes.len(), Self::ENTRIES.len());
497
498 old.mutes
499 .iter_mut()
500 .zip(params.mutes.iter())
501 .zip(Self::ENTRIES)
502 .filter(|((o, n), _)| !n.eq(o))
503 .try_for_each(|((old, &new), entry)| {
504 let &(func_block_id, audio_ch) = entry;
505
506 let mut op = AudioFeature::new(
507 func_block_id,
508 CtlAttr::Current,
509 audio_ch,
510 FeatureCtl::Mute(vec![new]),
511 );
512 avc.control(&AUDIO_SUBUNIT_0_ADDR, &mut op, timeout_ms)
513 .map(|_| *old = new)
514 })
515 }
516}
517
518#[derive(Debug, Clone, PartialEq, Eq)]
521pub struct AvcSelectorParameters {
522 pub selectors: Vec<usize>,
524}
525
526pub trait AvcSelectorOperation {
528 const FUNC_BLOCK_ID_LIST: &'static [u8];
530 const INPUT_PLUG_ID_LIST: &'static [u8];
532
533 fn create_selector_parameters() -> AvcSelectorParameters {
535 AvcSelectorParameters {
536 selectors: vec![Default::default(); Self::FUNC_BLOCK_ID_LIST.len()],
537 }
538 }
539
540 fn cache_selectors(
542 avc: &BebobAvc,
543 params: &mut AvcSelectorParameters,
544 timeout_ms: u32,
545 ) -> Result<(), Error> {
546 assert_eq!(params.selectors.len(), Self::FUNC_BLOCK_ID_LIST.len());
547
548 params
549 .selectors
550 .iter_mut()
551 .zip(Self::FUNC_BLOCK_ID_LIST)
552 .try_for_each(|(selector, &func_block_id)| {
553 let mut op = AudioSelector::new(func_block_id, CtlAttr::Current, 0xff);
554 avc.status(&AUDIO_SUBUNIT_0_ADDR, &mut op, timeout_ms)?;
555
556 Self::INPUT_PLUG_ID_LIST
557 .iter()
558 .position(|&input_plug_id| input_plug_id == op.input_plug_id)
559 .ok_or_else(|| {
560 let msg = format!(
561 "Unexpected index of input plug number: {}",
562 op.input_plug_id
563 );
564 Error::new(FileError::Io, &msg)
565 })
566 .map(|pos| *selector = pos)
567 })
568 }
569
570 fn update_selectors(
572 avc: &BebobAvc,
573 params: &AvcSelectorParameters,
574 old: &mut AvcSelectorParameters,
575 timeout_ms: u32,
576 ) -> Result<(), Error> {
577 assert_eq!(params.selectors.len(), Self::FUNC_BLOCK_ID_LIST.len());
578 assert_eq!(old.selectors.len(), Self::FUNC_BLOCK_ID_LIST.len());
579
580 old.selectors
581 .iter_mut()
582 .zip(params.selectors.iter())
583 .zip(Self::FUNC_BLOCK_ID_LIST)
584 .filter(|((o, n), _)| !o.eq(n))
585 .try_for_each(|((old, &new), &func_block_id)| {
586 let mut op = AudioSelector::new(func_block_id, CtlAttr::Current, new as u8);
587 avc.control(&AUDIO_SUBUNIT_0_ADDR, &mut op, timeout_ms)
588 .map(|_| *old = new)
589 })
590 }
591}