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 January 19, 2024 +.Dd January 29, 2024 .Dt SND_HDSPE 4 .Os .Sh NAME @@ -76,6 +76,10 @@ the respective device number in place of .Ql 0 . .Bl -tag -width indent +.It Va dev.hdspe.0.sample_rate +Set a fixed sample rate from 32000, 44100, 48000, up to 192000. +This is usually required for digital connections (AES, S/PDIF, ADAT). +The default value of 0 adjusts the sample rate according to pcm device settings. .It Va dev.hdspe.0.period The number of samples processed per interrupt, from 32, 64, 128, up to 4096. Setting a lower value here results in less latency, but increases system load diff --git a/sys/dev/sound/pci/hdspe-pcm.c b/sys/dev/sound/pci/hdspe-pcm.c --- a/sys/dev/sound/pci/hdspe-pcm.c +++ b/sys/dev/sound/pci/hdspe-pcm.c @@ -814,6 +814,9 @@ if (hdspe_running(sc) == 1) goto end; + if (sc->force_speed > 0) + speed = sc->force_speed; + /* First look for equal frequency. */ for (i = 0; rate_map[i].speed != 0; i++) { if (rate_map[i].speed == speed) 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 @@ -228,6 +228,7 @@ uint32_t period; uint32_t speed; uint32_t force_period; + uint32_t force_speed; }; #define hdspe_read_1(sc, regno) \ 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 @@ -228,6 +228,41 @@ } } +static int +hdspe_sysctl_sample_rate(SYSCTL_HANDLER_ARGS) +{ + struct sc_info *sc = oidp->oid_arg1; + int error; + unsigned int speed, multiplier; + + speed = sc->force_speed; + + /* Process sysctl (unsigned) integer request. */ + error = sysctl_handle_int(oidp, &speed, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + + /* Speed from 32000 to 192000, 0 falls back to pcm speed setting. */ + sc->force_speed = 0; + if (speed > 0) { + multiplier = 1; + if (speed > (96000 + 128000) / 2) + multiplier = 4; + else if (speed > (48000 + 64000) / 2) + multiplier = 2; + + if (speed < ((32000 + 44100) / 2) * multiplier) + sc->force_speed = 32000 * multiplier; + else if (speed < ((44100 + 48000) / 2) * multiplier) + sc->force_speed = 44100 * multiplier; + else + sc->force_speed = 48000 * multiplier; + } + + return (0); +} + + static int hdspe_sysctl_period(SYSCTL_HANDLER_ARGS) { @@ -455,6 +490,7 @@ /* Set rate. */ sc->speed = HDSPE_SPEED_DEFAULT; + sc->force_speed = 0; sc->ctrl_register &= ~HDSPE_FREQ_MASK; sc->ctrl_register |= HDSPE_FREQ_MASK_DEFAULT; hdspe_write_4(sc, HDSPE_CONTROL_REG, sc->ctrl_register); @@ -562,6 +598,12 @@ sc, 0, hdspe_sysctl_period, "A", "Force period of samples per interrupt (32, 64, ... 4096)"); + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "sample_rate", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, + sc, 0, hdspe_sysctl_sample_rate, "A", + "Force sample rate (32000, 44100, 48000, ... 192000)"); + return (bus_generic_attach(dev)); }