Re: snd-firewire-ctl-services: Digidesign Digi-002R - missing control for 'Optical mode'

[email protected]
Newsgroups org.alsa-project.alsa-devel
Message-ID <[email protected]>
On 2026-05-11 22:19, Takashi Sakamoto wrote:

> Yes. The service program provides no ALSA control element set
> for this purpose, because Digi 002 differs from Digi 003 in how it
> selects the source of S/PDIF signals for audio data in IEEE 1394
> isochronous packets sent to the host system.
> 

I experimented some more, and was able to muddle through the Rust code 
to 'move' the control (from 003 protocol) to act on the 002. This showed 
that the 002R does actually support this function.

I found a couple of things:
1). Parameter is not saved unless the Jack server is stopped before 
making the change. I think that this is expected.
--
simon@EliteBook:~/snd-firewire-ctl-services.github$ amixer -c 2 cset 
numid=8 'S/PDIF'
numid=8,iface=MIXER,name='optical-interface'
   ; type=ENUMERATED,access=rw------,values=1,items=2
   ; Item #0 'ADAT'
   ; Item #1 'S/PDIF'
   : values=1
simon@EliteBook:~/snd-firewire-ctl-services.github$ amixer -c 2 cget 
numid=8
numid=8,iface=MIXER,name='optical-interface'
   ; type=ENUMERATED,access=rw------,values=1,items=2
   ; Item #0 'ADAT'
   ; Item #1 'S/PDIF'
   : values=1
--

2). With 'loop backs' on the RCA and Optical ports I got all channels in 
'normal/ADAT' mode, but in the 'S/PDIF' mode the path was re-assigned. I 
got nothing through channels 11..18 (normally ADAT/optical), instead 
only channels 9..10 passed audio - HOWEVER these are going over the 
optical fibre (not co-ax cable), unplug the fibre and this loop-back 
stops.

So in summary I think the existing code can be re-jigged to cover both 
002 and 003.
Simon.
Screenshot_2026-05-12_12-26-32.png (image/png, 151.8 KB) - not displayed
20260512_hacky_adat.patch (text/x-diff, 5.3 KB)
diff --git a/protocols/digi00x/src/lib.rs b/protocols/digi00x/src/lib.rs
index 06942da3..4f4ac697 100644
--- a/protocols/digi00x/src/lib.rs
+++ b/protocols/digi00x/src/lib.rs
@@ -277,7 +277,7 @@ impl Default for OpticalInterfaceMode {
     }
 }
 
-impl Dg00xWhollyCachableParamsOperation<OpticalInterfaceMode> for Digi003Protocol {
+impl Dg00xWhollyCachableParamsOperation<OpticalInterfaceMode> for Digi002Protocol {
     fn cache_wholly(
         req: &mut FwReq,
         node: &mut FwNode,
@@ -294,7 +294,7 @@ impl Dg00xWhollyCachableParamsOperation<OpticalInterfaceMode> for Digi003Protoco
     }
 }
 
-impl Dg00xWhollyUpdatableParamsOperation<OpticalInterfaceMode> for Digi003Protocol {
+impl Dg00xWhollyUpdatableParamsOperation<OpticalInterfaceMode> for Digi002Protocol {
     fn update_wholly(
         req: &mut FwReq,
         node: &mut FwNode,
diff --git a/runtime/digi00x/src/model.rs b/runtime/digi00x/src/model.rs
index 4e164936..babccf46 100644
--- a/runtime/digi00x/src/model.rs
+++ b/runtime/digi00x/src/model.rs
@@ -11,6 +11,7 @@ pub struct Digi002Model {
     common_ctl: CommonCtl<Digi002Protocol>,
     meter_ctl: MeterCtl<Digi002Protocol>,
     monitor_ctl: MonitorCtl<Digi002Protocol>,
+    opt_iface_ctl: OpticalIfaceCtl,
 }
 
 impl CtlModel<(SndDigi00x, FwNode)> for Digi002Model {
@@ -19,6 +20,7 @@ impl CtlModel<(SndDigi00x, FwNode)> for Digi002Model {
         self.meter_ctl.cache(&mut self.req, node, TIMEOUT_MS)?;
         self.monitor_ctl
             .cache(unit, &mut self.req, node, TIMEOUT_MS)?;
+        self.opt_iface_ctl.cache(&mut self.req, node, TIMEOUT_MS)?;
         Ok(())
     }
 
@@ -26,6 +28,7 @@ impl CtlModel<(SndDigi00x, FwNode)> for Digi002Model {
         self.common_ctl.load(card_cntr)?;
         self.meter_ctl.load(card_cntr)?;
         self.monitor_ctl.load(card_cntr)?;
+        self.opt_iface_ctl.load(card_cntr)?;
         Ok(())
     }
 
@@ -36,6 +39,8 @@ impl CtlModel<(SndDigi00x, FwNode)> for Digi002Model {
             Ok(true)
         } else if self.monitor_ctl.read(elem_id, elem_value)? {
             Ok(true)
+        } else if self.opt_iface_ctl.read(elem_id, elem_value)? {
+            Ok(true)
         } else {
             Ok(false)
         }
@@ -61,6 +66,15 @@ impl CtlModel<(SndDigi00x, FwNode)> for Digi002Model {
             TIMEOUT_MS,
         )? {
             Ok(true)
+        } else if self.opt_iface_ctl.write(
+            unit,
+            &mut self.req,
+            node,
+            elem_id,
+            elem_value,
+            TIMEOUT_MS,
+        )? {
+            Ok(true)
         } else {
             Ok(false)
         }
@@ -103,7 +117,7 @@ pub struct Digi003Model {
     common_ctl: CommonCtl<Digi003Protocol>,
     meter_ctl: MeterCtl<Digi003Protocol>,
     monitor_ctl: MonitorCtl<Digi003Protocol>,
-    opt_iface_ctl: OpticalIfaceCtl,
+    //opt_iface_ctl: OpticalIfaceCtl,
 }
 
 impl CtlModel<(SndDigi00x, FwNode)> for Digi003Model {
@@ -112,7 +126,7 @@ impl CtlModel<(SndDigi00x, FwNode)> for Digi003Model {
         self.meter_ctl.cache(&mut self.req, node, TIMEOUT_MS)?;
         self.monitor_ctl
             .cache(unit, &mut self.req, node, TIMEOUT_MS)?;
-        self.opt_iface_ctl.cache(&mut self.req, node, TIMEOUT_MS)?;
+        //self.opt_iface_ctl.cache(&mut self.req, node, TIMEOUT_MS)?;
         Ok(())
     }
 
@@ -120,7 +134,7 @@ impl CtlModel<(SndDigi00x, FwNode)> for Digi003Model {
         self.common_ctl.load(card_cntr)?;
         self.meter_ctl.load(card_cntr)?;
         self.monitor_ctl.load(card_cntr)?;
-        self.opt_iface_ctl.load(card_cntr)?;
+        //self.opt_iface_ctl.load(card_cntr)?;
         Ok(())
     }
 
@@ -131,8 +145,8 @@ impl CtlModel<(SndDigi00x, FwNode)> for Digi003Model {
             Ok(true)
         } else if self.monitor_ctl.read(elem_id, elem_value)? {
             Ok(true)
-        } else if self.opt_iface_ctl.read(elem_id, elem_value)? {
-            Ok(true)
+        //} else if self.opt_iface_ctl.read(elem_id, elem_value)? {
+        //    Ok(true)
         } else {
             Ok(false)
         }
@@ -158,15 +172,6 @@ impl CtlModel<(SndDigi00x, FwNode)> for Digi003Model {
             TIMEOUT_MS,
         )? {
             Ok(true)
-        } else if self.opt_iface_ctl.write(
-            unit,
-            &mut self.req,
-            node,
-            elem_id,
-            elem_value,
-            TIMEOUT_MS,
-        )? {
-            Ok(true)
         } else {
             Ok(false)
         }
@@ -387,7 +392,7 @@ impl OpticalIfaceCtl {
         &[OpticalInterfaceMode::Adat, OpticalInterfaceMode::Spdif];
 
     fn cache(&mut self, req: &mut FwReq, node: &mut FwNode, timeout_ms: u32) -> Result<(), Error> {
-        let res = Digi003Protocol::cache_wholly(req, node, &mut self.opt_iface_mode, timeout_ms);
+        let res = Digi002Protocol::cache_wholly(req, node, &mut self.opt_iface_mode, timeout_ms);
         debug!(params = ?self.opt_iface_mode, ?res);
         res
     }
@@ -444,7 +449,7 @@ impl OpticalIfaceCtl {
                         Error::new(FileError::Inval, &msg)
                     })
                     .copied()?;
-                let res = Digi003Protocol::update_wholly(req, node, &params, timeout_ms)
+                let res = Digi002Protocol::update_wholly(req, node, &params, timeout_ms)
                     .map(|_| self.opt_iface_mode = params);
                 debug!(params = ?self.opt_iface_mode, ?res);
                 res.map(|_| true)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.