[PATCH] sound: pci/rme9652 - implement and expose controls for output

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>From 980aa253c17d233966e05a43f3611693e2e02040 Mon Sep 17 00:00:00 2001
From: Jasmin Fazlic <superfassl@xxxxxxxxx>
Date: Sun, 31 Jan 2021 22:17:22 +0100
Subject: [PATCH] sound: pci/rme9652 - implement and expose controls for output
 loopback

- so far only tested and enabled for RME HDSP9632

Signed-off-by: Jasmin Fazlic <superfassl@xxxxxxxxx>
---
 sound/pci/rme9652/hdsp.c | 85 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 84 insertions(+), 1 deletion(-)

diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index cea53a878c36..7e832a502cea 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -469,6 +469,7 @@ struct hdsp {
     unsigned char          qs_out_channels;
     unsigned char         ds_out_channels;
     unsigned char         ss_out_channels;
+    u32                   io_loopback;          /* output loopback channel states*/
 
     struct snd_dma_buffer capture_dma_buf;
     struct snd_dma_buffer playback_dma_buf;
@@ -3253,6 +3254,71 @@ static const struct snd_kcontrol_new snd_hdsp_96xx_aeb =
             HDSP_AnalogExtensionBoard);
 static struct snd_kcontrol_new snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK;
 
+
+static bool hdsp_loopback_get(struct hdsp *const hdsp, const u8 channel)
+{
+    return hdsp->io_loopback & (1 << channel);
+}
+
+static int hdsp_loopback_set(struct hdsp *const hdsp, const u8 channel, const bool enable)
+{
+    if (hdsp_loopback_get(hdsp, channel) == enable)
+        return 0;
+
+    hdsp->io_loopback ^= (1 << channel);
+
+    hdsp_write(hdsp, HDSP_inputEnable + (4 * (hdsp->max_channels + channel)), enable);
+
+    return 1;
+}
+
+static int snd_hdsp_loopback_info(struct snd_kcontrol *const kcontrol,
+                  struct snd_ctl_elem_info *const uinfo)
+{
+    uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+    uinfo->count = 1;
+    uinfo->value.integer.min = 0;
+    uinfo->value.integer.max = 1;
+    return 0;
+}
+
+static int snd_hdsp_loopback_get(struct snd_kcontrol *const kcontrol,
+                 struct snd_ctl_elem_value *const ucontrol)
+{
+    struct hdsp *const hdsp = snd_kcontrol_chip(kcontrol);
+    const u8 channel = kcontrol->id.index;
+
+    if (channel >= hdsp->max_channels)
+        return -ENOENT;
+
+    ucontrol->value.integer.value[0] = hdsp_loopback_get(hdsp, channel);
+
+    return 0;
+}
+
+static int snd_hdsp_loopback_put(struct snd_kcontrol *const kcontrol,
+                 struct snd_ctl_elem_value *const ucontrol)
+{
+    struct hdsp *const hdsp = snd_kcontrol_chip(kcontrol);
+    const u8 channel = ucontrol->id.index;
+    const bool enable = ucontrol->value.integer.value[0] & 1;
+
+    if (channel >= hdsp->max_channels)
+        return -ENOENT;
+
+    return hdsp_loopback_set(hdsp, channel, enable);
+}
+
+static struct snd_kcontrol_new snd_hdsp_loopback_control = {
+    .iface = SNDRV_CTL_ELEM_IFACE_HWDEP,
+    .name = "Output Loopback",
+    .index = 0,
+    .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+    .info = snd_hdsp_loopback_info,
+    .get = snd_hdsp_loopback_get,
+    .put = snd_hdsp_loopback_put
+};
+
 static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
 {
     unsigned int idx;
@@ -3297,6 +3363,17 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
         }
     }
 
+    /* Output loopback controls for H9632 cards */
+    if (hdsp->io_type == H9632) {
+        for (idx = 0; idx < hdsp->max_channels; idx++) {
+            snd_hdsp_loopback_control.index = idx;
+            kctl = snd_ctl_new1(&snd_hdsp_loopback_control, hdsp);
+            err = snd_ctl_add(card, kctl);
+            if (err < 0)
+                return err;
+        }
+    }
+
     /* AEB control for H96xx card */
     if (hdsp->io_type == H9632 || hdsp->io_type == H9652) {
         if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_96xx_aeb, hdsp))) < 0)
@@ -4956,7 +5033,7 @@ static int snd_hdsp_enable_io (struct hdsp *hdsp)
 
 static void snd_hdsp_initialize_channels(struct hdsp *hdsp)
 {
-    int status, aebi_channels, aebo_channels;
+    int status, aebi_channels, aebo_channels, i;
 
     switch (hdsp->io_type) {
     case Digiface:
@@ -4983,6 +5060,12 @@ static void snd_hdsp_initialize_channels(struct hdsp *hdsp)
         hdsp->ss_out_channels = H9632_SS_CHANNELS+aebo_channels;
         hdsp->ds_out_channels = H9632_DS_CHANNELS+aebo_channels;
         hdsp->qs_out_channels = H9632_QS_CHANNELS+aebo_channels;
+        /* Disable loopback of output channels, as the set function
+         * only sets on a change we fake all bits (channels) as enabled.
+         */
+        hdsp->io_loopback = 0xffffffff;
+        for (i = 0; i < hdsp->max_channels; ++i)
+            hdsp_loopback_set(hdsp, i, false);
         break;
 
     case Multiface:
-- 
2.27.0





[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Pulse Audio]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux