From nobody Tue Dec 03 22:32:24 2024 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Y2wQ10Kvzz5gryr; Tue, 03 Dec 2024 22:32:25 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Y2wQ05rDtz51vC; Tue, 3 Dec 2024 22:32:24 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1733265144; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=d6TTDpju/OHC/HNVeEiiKdpSOYlesfCyl3uPbw6zsSE=; b=u2s9hJDVGYT9MRswijMxtEy/3kZAxVx6AW+aktONTdNZzn3K78vPHFXYfud5Kzn1bIgPtq nGNfCkydyiVDxGvnwrEGrlkUbO48GmBDxPGlm1Jep34N8QLxdjj4uePmE5QDH0frOPTFEL yYHO+lMATzr1MSEA+9fdLRGCQG1rPETo5B0mOoOKqyzuAMRnm8cvOKCp7X3GoHYj4nJRNi OUwEeflFTd+FSvb72+TmKgPjcHf3C582fjQmYCMfuSUM7vtxRz6jBofi10lplN/ccKHbmd QVwocJw0pJm4NzSbm7udlM+6Pnbbqud6anw/TuSwwEY6u/Q5bXyYHD6bZgAG5Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1733265144; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=d6TTDpju/OHC/HNVeEiiKdpSOYlesfCyl3uPbw6zsSE=; b=X2YzEhXxmLF8r9qPZCUa82Z8vPkXfEyQ0x4uviM0QYrDLnvOYE5K9xE/EPmZw7k+oF6Oiv O1xo47223eVazYlAIkKP4AyMaaaDwQz2U0Yd0vMYFvFmXGnt0ALysoPD7HjPq0e/Xd6jXu GEJVr4r/yUGww5Z+pMJ30b+gfRCrDtaNXexNBSaWQP4vBdr48pfD4UXy7TCA2Xdq5v0RnV SnIbqfnrDOo8cjBFNz1XMojnFLmK73PKGOP9u2z68DGFH0KKd0aJjdESE4GSoIocqT7PIz lFZl1iN+IdhwxVQj+PuLy6N7sZcZ5N/3Oy17y7k813Xq8z46CG3Vcwof+hcxoA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1733265144; a=rsa-sha256; cv=none; b=pzS/Q3mX1e9EuP0CZ0m7Q0sJ1xjwRYDrLULr7t1vyN5lhP/WjwZzBI9ctdn1OGTFk6kn9U 5TcGTrTqOkz9WePjuzSkz9k1orRoRXRlOr1jA3tZvKLoPAE4jUW5reichTWUdkT4RBZU7Q wXNFXtUsZMZkjteiU1GGn4TPoCK/nNnzOVYRLo/T/FiU3YM5Bc+fM9VfnTuFeAF1ld+jhb FWX+gMYpwFfpyVDxTR6IFq952isdqlqFzc8DRxaBjrURMUm2jgLxWeT+x9J8+WkMHj2iK6 5Kmxfz49LIdRXr/sujz6LONfvTEXTO/aB0rQKkEHKS7HKYFgTu0qdDukfcW4WQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Y2wQ056lszhNV; Tue, 3 Dec 2024 22:32:24 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 4B3MWOnY038456; Tue, 3 Dec 2024 22:32:24 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 4B3MWOHX038453; Tue, 3 Dec 2024 22:32:24 GMT (envelope-from git) Date: Tue, 3 Dec 2024 22:32:24 GMT Message-Id: <202412032232.4B3MWOHX038453@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Ruslan Bukin Subject: git: 49a7f2b31329 - main - snd_hdspe(4): Add sysctls to select analog signal levels. List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: br X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 49a7f2b31329b7bf9d986f1ae1f8a2c5397c6563 Auto-Submitted: auto-generated The branch main has been updated by br: URL: https://cgit.FreeBSD.org/src/commit/?id=49a7f2b31329b7bf9d986f1ae1f8a2c5397c6563 commit 49a7f2b31329b7bf9d986f1ae1f8a2c5397c6563 Author: Florian Walpen AuthorDate: 2024-12-03 22:27:47 +0000 Commit: Ruslan Bukin CommitDate: 2024-12-03 22:31:50 +0000 snd_hdspe(4): Add sysctls to select analog signal levels. RME HDSPE AIO sound cards support different sensitivity levels at the analog input, and different gain levels for the analog line and phones outputs. Expose these settings as sysctl tunables. Test Plan: The following tests on hardware should be performed if possible: - Phones output volume changes according to sysctl setting (caution, still extremely loud). - Create loop to feedback the line output to line input, recording the sound played. - Iterate through input signal levels and observe volume changes in recorded audio. - Iterate through output signal levels and observe volume changes in recorded audio. Reviewed by: br, christos Differential Revision: https://reviews.freebsd.org/D47412 --- share/man/man4/snd_hdspe.4 | 28 +++++- sys/dev/sound/pci/hdspe.c | 222 +++++++++++++++++++++++++++++++++++++++++++++ sys/dev/sound/pci/hdspe.h | 56 +++++++----- 3 files changed, 281 insertions(+), 25 deletions(-) diff --git a/share/man/man4/snd_hdspe.4 b/share/man/man4/snd_hdspe.4 index ac81356fb783..35dea518da64 100644 --- 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 @@ for accurately synchronized signals (required for recording digital 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.c b/sys/dev/sound/pci/hdspe.c index 2561fcdebb1c..f983f0be2275 100644 --- a/sys/dev/sound/pci/hdspe.c +++ b/sys/dev/sound/pci/hdspe.c @@ -246,6 +246,198 @@ hdspe_map_dmabuf(struct sc_info *sc) } } +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->settings_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->settings_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->settings_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 @@ hdspe_init(struct sc_info *sc) /* 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 @@ hdspe_attach(device_t dev) 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)); } diff --git a/sys/dev/sound/pci/hdspe.h b/sys/dev/sound/pci/hdspe.h index 2f0bdddd930f..bced78758068 100644 --- 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_HIGHGAIN 0 +#define HDSPE_OUTPUT_LEVEL_PLUS4DBU (HDSPE_SETTINGS_OUTPUT_GAIN0) +#define HDSPE_OUTPUT_LEVEL_MINUS10DBV (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_HIGHGAIN 0 +#define HDSPE_PHONES_LEVEL_PLUS4DBU (HDSPE_SETTINGS_PHONES_GAIN0) +#define HDSPE_PHONES_LEVEL_MINUS10DBV (HDSPE_SETTINGS_PHONES_GAIN1) + +/* Control register flags */ #define HDSPE_ENABLE (1 << 0) /* Interrupts */