Page MenuHomeFreeBSD

D47412.diff
No OneTemporary

D47412.diff

diff --git a/share/man/man4/snd_hdspe.4 b/share/man/man4/snd_hdspe.4
--- a/share/man/man4/snd_hdspe.4
+++ b/share/man/man4/snd_hdspe.4
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd September 28, 2024
+.Dd November 2, 2024
.Dt SND_HDSPE 4
.Os
.Sh NAME
@@ -132,6 +132,32 @@
audio).
.El
.Pp
+The following tunables are applicable to HDSPe AIO devices only:
+.Bl -tag -width indent
+.It Va dev.hdspe.0.input_level
+Select the sensitivity of the analog line input.
+Available reference levels for the input signal are
+.Ql LowGain ,
+.Ql +4dBu
+and
+.Ql -10dBV .
+.It Va dev.hdspe.0.output_level
+Select the gain level of the analog line output.
+Available reference levels for the output signal are
+.Ql HighGain ,
+.Ql +4dBu
+and
+.Ql -10dBV .
+.It Va dev.hdspe.0.phones_level
+Adjust the gain level of the phones output, separately from the analog line
+output.
+Available reference levels for the output signal are
+.Ql HighGain ,
+.Ql +4dBu
+and
+.Ql -10dBV .
+.El
+.Pp
Where appropriate these sysctl values are modeled after official RME software on
other platforms, and adopt their terminology.
Consult the RME user manuals for additional information.
diff --git a/sys/dev/sound/pci/hdspe.h b/sys/dev/sound/pci/hdspe.h
--- a/sys/dev/sound/pci/hdspe.h
+++ b/sys/dev/sound/pci/hdspe.h
@@ -74,35 +74,43 @@
#define HDSPE_LAT_BYTES_MIN (32 * 4)
#define hdspe_encode_latency(x) (((x)<<1) & HDSPE_LAT_MASK)
-/* Gain */
-#define HDSP_ADGain0 (1 << 25)
-#define HDSP_ADGain1 (1 << 26)
-#define HDSP_DAGain0 (1 << 27)
-#define HDSP_DAGain1 (1 << 28)
-#define HDSP_PhoneGain0 (1 << 29)
-#define HDSP_PhoneGain1 (1 << 30)
-
-#define HDSP_ADGainMask (HDSP_ADGain0 | HDSP_ADGain1)
-#define HDSP_ADGainMinus10dBV (HDSP_ADGainMask)
-#define HDSP_ADGainPlus4dBu (HDSP_ADGain0)
-#define HDSP_ADGainLowGain 0
-
-#define HDSP_DAGainMask (HDSP_DAGain0 | HDSP_DAGain1)
-#define HDSP_DAGainHighGain (HDSP_DAGainMask)
-#define HDSP_DAGainPlus4dBu (HDSP_DAGain0)
-#define HDSP_DAGainMinus10dBV 0
-
-#define HDSP_PhoneGainMask (HDSP_PhoneGain0|HDSP_PhoneGain1)
-#define HDSP_PhoneGain0dB HDSP_PhoneGainMask
-#define HDSP_PhoneGainMinus6dB (HDSP_PhoneGain0)
-#define HDSP_PhoneGainMinus12dB 0
-
-/* Settings */
+/* Register addresses */
#define HDSPE_SETTINGS_REG 0
#define HDSPE_CONTROL_REG 64
#define HDSPE_STATUS_REG 0
#define HDSPE_STATUS1_REG 64
#define HDSPE_STATUS2_REG 192
+
+/* Settings register flags */
+#define HDSPE_SETTINGS_INPUT_GAIN0 (1 << 20)
+#define HDSPE_SETTINGS_INPUT_GAIN1 (1 << 21)
+#define HDSPE_SETTINGS_OUTPUT_GAIN0 (1 << 22)
+#define HDSPE_SETTINGS_OUTPUT_GAIN1 (1 << 23)
+#define HDSPE_SETTINGS_PHONES_GAIN0 (1 << 24)
+#define HDSPE_SETTINGS_PHONES_GAIN1 (1 << 25)
+
+/* Analog input gain level */
+#define HDSPE_INPUT_LEVEL_MASK (HDSPE_SETTINGS_INPUT_GAIN0 | \
+ HDSPE_SETTINGS_INPUT_GAIN1)
+#define HDSPE_INPUT_LEVEL_LOWGAIN 0
+#define HDSPE_INPUT_LEVEL_PLUS4DBU (HDSPE_SETTINGS_INPUT_GAIN0)
+#define HDSPE_INPUT_LEVEL_MINUS10DBV (HDSPE_SETTINGS_INPUT_GAIN1)
+
+/* Analog output gain level */
+#define HDSPE_OUTPUT_LEVEL_MASK (HDSPE_SETTINGS_OUTPUT_GAIN0 | \
+ HDSPE_SETTINGS_OUTPUT_GAIN1)
+#define HDSPE_OUTPUT_LEVEL_MINUS10DBV 0
+#define HDSPE_OUTPUT_LEVEL_PLUS4DBU (HDSPE_SETTINGS_OUTPUT_GAIN0)
+#define HDSPE_OUTPUT_LEVEL_HIGHGAIN (HDSPE_SETTINGS_OUTPUT_GAIN1)
+
+/* Phones output gain level */
+#define HDSPE_PHONES_LEVEL_MASK (HDSPE_SETTINGS_PHONES_GAIN0 | \
+ HDSPE_SETTINGS_PHONES_GAIN1)
+#define HDSPE_PHONES_LEVEL_MINUS10DBV 0
+#define HDSPE_PHONES_LEVEL_PLUS4DBU (HDSPE_SETTINGS_PHONES_GAIN0)
+#define HDSPE_PHONES_LEVEL_HIGHGAIN (HDSPE_SETTINGS_PHONES_GAIN1)
+
+/* Control register flags */
#define HDSPE_ENABLE (1 << 0)
/* Interrupts */
diff --git a/sys/dev/sound/pci/hdspe.c b/sys/dev/sound/pci/hdspe.c
--- a/sys/dev/sound/pci/hdspe.c
+++ b/sys/dev/sound/pci/hdspe.c
@@ -246,6 +246,198 @@
}
}
+static const char *
+hdspe_settings_input_level(uint32_t settings)
+{
+ switch (settings & HDSPE_INPUT_LEVEL_MASK) {
+ case HDSPE_INPUT_LEVEL_LOWGAIN:
+ return ("LowGain");
+ case HDSPE_INPUT_LEVEL_PLUS4DBU:
+ return ("+4dBu");
+ case HDSPE_INPUT_LEVEL_MINUS10DBV:
+ return ("-10dBV");
+ default:
+ return (NULL);
+ }
+}
+
+static int
+hdspe_sysctl_input_level(SYSCTL_HANDLER_ARGS)
+{
+ struct sc_info *sc;
+ const char *label;
+ char buf[16] = "invalid";
+ int error;
+ uint32_t settings;
+
+ sc = oidp->oid_arg1;
+
+ /* Only available on HDSPE AIO. */
+ if (sc->type != HDSPE_AIO)
+ return (ENXIO);
+
+ /* Extract current input level from settings register. */
+ settings = sc->settings_register & HDSPE_INPUT_LEVEL_MASK;
+ label = hdspe_settings_input_level(settings);
+ if (label != NULL)
+ strlcpy(buf, label, sizeof(buf));
+
+ /* Process sysctl string request. */
+ error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ /* Find input level matching the sysctl string. */
+ label = hdspe_settings_input_level(HDSPE_INPUT_LEVEL_LOWGAIN);
+ if (strncasecmp(buf, label, sizeof(buf)) == 0)
+ settings = HDSPE_INPUT_LEVEL_LOWGAIN;
+ label = hdspe_settings_input_level(HDSPE_INPUT_LEVEL_PLUS4DBU);
+ if (strncasecmp(buf, label, sizeof(buf)) == 0)
+ settings = HDSPE_INPUT_LEVEL_PLUS4DBU;
+ label = hdspe_settings_input_level(HDSPE_INPUT_LEVEL_MINUS10DBV);
+ if (strncasecmp(buf, label, sizeof(buf)) == 0)
+ settings = HDSPE_INPUT_LEVEL_MINUS10DBV;
+
+ /* Set input level in settings register. */
+ settings &= HDSPE_INPUT_LEVEL_MASK;
+ if (settings != (sc->ctrl_register & HDSPE_INPUT_LEVEL_MASK)) {
+ snd_mtxlock(sc->lock);
+ sc->settings_register &= ~HDSPE_INPUT_LEVEL_MASK;
+ sc->settings_register |= settings;
+ hdspe_write_4(sc, HDSPE_SETTINGS_REG, sc->settings_register);
+ snd_mtxunlock(sc->lock);
+ }
+ return (0);
+}
+
+static const char *
+hdspe_settings_output_level(uint32_t settings)
+{
+ switch (settings & HDSPE_OUTPUT_LEVEL_MASK) {
+ case HDSPE_OUTPUT_LEVEL_HIGHGAIN:
+ return ("HighGain");
+ case HDSPE_OUTPUT_LEVEL_PLUS4DBU:
+ return ("+4dBu");
+ case HDSPE_OUTPUT_LEVEL_MINUS10DBV:
+ return ("-10dBV");
+ default:
+ return (NULL);
+ }
+}
+
+static int
+hdspe_sysctl_output_level(SYSCTL_HANDLER_ARGS)
+{
+ struct sc_info *sc;
+ const char *label;
+ char buf[16] = "invalid";
+ int error;
+ uint32_t settings;
+
+ sc = oidp->oid_arg1;
+
+ /* Only available on HDSPE AIO. */
+ if (sc->type != HDSPE_AIO)
+ return (ENXIO);
+
+ /* Extract current output level from settings register. */
+ settings = sc->settings_register & HDSPE_OUTPUT_LEVEL_MASK;
+ label = hdspe_settings_output_level(settings);
+ if (label != NULL)
+ strlcpy(buf, label, sizeof(buf));
+
+ /* Process sysctl string request. */
+ error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ /* Find output level matching the sysctl string. */
+ label = hdspe_settings_output_level(HDSPE_OUTPUT_LEVEL_HIGHGAIN);
+ if (strncasecmp(buf, label, sizeof(buf)) == 0)
+ settings = HDSPE_OUTPUT_LEVEL_HIGHGAIN;
+ label = hdspe_settings_output_level(HDSPE_OUTPUT_LEVEL_PLUS4DBU);
+ if (strncasecmp(buf, label, sizeof(buf)) == 0)
+ settings = HDSPE_OUTPUT_LEVEL_PLUS4DBU;
+ label = hdspe_settings_output_level(HDSPE_OUTPUT_LEVEL_MINUS10DBV);
+ if (strncasecmp(buf, label, sizeof(buf)) == 0)
+ settings = HDSPE_OUTPUT_LEVEL_MINUS10DBV;
+
+ /* Set output level in settings register. */
+ settings &= HDSPE_OUTPUT_LEVEL_MASK;
+ if (settings != (sc->ctrl_register & HDSPE_OUTPUT_LEVEL_MASK)) {
+ snd_mtxlock(sc->lock);
+ sc->settings_register &= ~HDSPE_OUTPUT_LEVEL_MASK;
+ sc->settings_register |= settings;
+ hdspe_write_4(sc, HDSPE_SETTINGS_REG, sc->settings_register);
+ snd_mtxunlock(sc->lock);
+ }
+ return (0);
+}
+
+static const char *
+hdspe_settings_phones_level(uint32_t settings)
+{
+ switch (settings & HDSPE_PHONES_LEVEL_MASK) {
+ case HDSPE_PHONES_LEVEL_HIGHGAIN:
+ return ("HighGain");
+ case HDSPE_PHONES_LEVEL_PLUS4DBU:
+ return ("+4dBu");
+ case HDSPE_PHONES_LEVEL_MINUS10DBV:
+ return ("-10dBV");
+ default:
+ return (NULL);
+ }
+}
+
+static int
+hdspe_sysctl_phones_level(SYSCTL_HANDLER_ARGS)
+{
+ struct sc_info *sc;
+ const char *label;
+ char buf[16] = "invalid";
+ int error;
+ uint32_t settings;
+
+ sc = oidp->oid_arg1;
+
+ /* Only available on HDSPE AIO. */
+ if (sc->type != HDSPE_AIO)
+ return (ENXIO);
+
+ /* Extract current phones level from settings register. */
+ settings = sc->settings_register & HDSPE_PHONES_LEVEL_MASK;
+ label = hdspe_settings_phones_level(settings);
+ if (label != NULL)
+ strlcpy(buf, label, sizeof(buf));
+
+ /* Process sysctl string request. */
+ error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ /* Find phones level matching the sysctl string. */
+ label = hdspe_settings_phones_level(HDSPE_PHONES_LEVEL_HIGHGAIN);
+ if (strncasecmp(buf, label, sizeof(buf)) == 0)
+ settings = HDSPE_PHONES_LEVEL_HIGHGAIN;
+ label = hdspe_settings_phones_level(HDSPE_PHONES_LEVEL_PLUS4DBU);
+ if (strncasecmp(buf, label, sizeof(buf)) == 0)
+ settings = HDSPE_PHONES_LEVEL_PLUS4DBU;
+ label = hdspe_settings_phones_level(HDSPE_PHONES_LEVEL_MINUS10DBV);
+ if (strncasecmp(buf, label, sizeof(buf)) == 0)
+ settings = HDSPE_PHONES_LEVEL_MINUS10DBV;
+
+ /* Set phones level in settings register. */
+ settings &= HDSPE_PHONES_LEVEL_MASK;
+ if (settings != (sc->ctrl_register & HDSPE_PHONES_LEVEL_MASK)) {
+ snd_mtxlock(sc->lock);
+ sc->settings_register &= ~HDSPE_PHONES_LEVEL_MASK;
+ sc->settings_register |= settings;
+ hdspe_write_4(sc, HDSPE_SETTINGS_REG, sc->settings_register);
+ snd_mtxunlock(sc->lock);
+ }
+ return (0);
+}
+
static int
hdspe_sysctl_sample_rate(SYSCTL_HANDLER_ARGS)
{
@@ -529,6 +721,15 @@
/* Other settings. */
sc->settings_register = 0;
+
+ /* Default gain levels. */
+ sc->settings_register &= ~HDSPE_INPUT_LEVEL_MASK;
+ sc->settings_register |= HDSPE_INPUT_LEVEL_LOWGAIN;
+ sc->settings_register &= ~HDSPE_OUTPUT_LEVEL_MASK;
+ sc->settings_register |= HDSPE_OUTPUT_LEVEL_MINUS10DBV;
+ sc->settings_register &= ~HDSPE_PHONES_LEVEL_MASK;
+ sc->settings_register |= HDSPE_PHONES_LEVEL_MINUS10DBV;
+
hdspe_write_4(sc, HDSPE_SETTINGS_REG, sc->settings_register);
return (0);
@@ -623,6 +824,27 @@
sc, 0, hdspe_sysctl_sample_rate, "A",
"Force sample rate (32000, 44100, 48000, ... 192000)");
+ if (sc->type == HDSPE_AIO) {
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "phones_level", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ sc, 0, hdspe_sysctl_phones_level, "A",
+ "Phones output level ('HighGain', '+4dBU', '-10dBV')");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "output_level", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ sc, 0, hdspe_sysctl_output_level, "A",
+ "Analog output level ('HighGain', '+4dBU', '-10dBV')");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "input_level", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ sc, 0, hdspe_sysctl_input_level, "A",
+ "Analog input level ('LowGain', '+4dBU', '-10dBV')");
+ }
+
+
return (bus_generic_attach(dev));
}

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 8, 12:43 AM (22 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14524184
Default Alt Text
D47412.diff (11 KB)

Event Timeline