snd_hdspe(4): Per device sysctl for period.

Let the user choose a period (interrupt cadence in samples), in the
official RME drivers this setting is available as "Buffer Size".
Override the period propagated through blocksize by pcm channel latency
settings (see sound(4)), since these are unreliable and differ between
playback and recording channels.

Differential Revision: https://reviews.freebsd.org/D43527
This commit is contained in:
Florian Walpen 2024-01-28 20:18:20 +00:00 committed by Ruslan Bukin
parent 8f7327dcee
commit fb87726303
4 changed files with 48 additions and 1 deletions

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd January 8, 2024
.Dd January 19, 2024
.Dt SND_HDSPE 4
.Os
.Sh NAME
@ -76,6 +76,11 @@ To adjust the following sysctl identifiers for a specific sound card, insert
the respective device number in place of
.Ql 0 .
.Bl -tag -width indent
.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
due to frequent interrupt processing.
Extreme values may cause audio gaps and glitches.
.It Va dev.hdspe.0.clock_list
Lists possible clock sources to sync with, depending on the hardware model.
This includes internal and external master clocks as well as incoming digital

View File

@ -891,6 +891,9 @@ hdspechan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
blocksize /= 4 /* samples */;
if (sc->force_period > 0)
blocksize = sc->force_period;
/* First look for equal latency. */
for (i = 0; latency_map[i].period != 0; i++) {
if (latency_map[i].period == blocksize)

View File

@ -228,6 +228,31 @@ hdspe_map_dmabuf(struct sc_info *sc)
}
}
static int
hdspe_sysctl_period(SYSCTL_HANDLER_ARGS)
{
struct sc_info *sc = oidp->oid_arg1;
int error;
unsigned int period;
period = sc->force_period;
/* Process sysctl (unsigned) integer request. */
error = sysctl_handle_int(oidp, &period, 0, req);
if (error != 0 || req->newptr == NULL)
return (error);
/* Period is from 2^5 to 2^14, 0 falls back to pcm latency settings. */
sc->force_period = 0;
if (period > 0) {
sc->force_period = 32;
while (sc->force_period < period && sc->force_period < 4096)
sc->force_period <<= 1;
}
return (0);
}
static int
hdspe_sysctl_clock_preference(SYSCTL_HANDLER_ARGS)
{
@ -419,6 +444,13 @@ hdspe_init(struct sc_info *sc)
/* Set latency. */
sc->period = 32;
/*
* The pcm channel latency settings propagate unreliable blocksizes,
* different for recording and playback, and skewed due to rounding
* and total buffer size limits.
* Force period to a consistent default until these issues are fixed.
*/
sc->force_period = 256;
sc->ctrl_register = hdspe_encode_latency(7);
/* Set rate. */
@ -524,6 +556,12 @@ hdspe_attach(device_t dev)
sc, 0, hdspe_sysctl_clock_list, "A",
"List of supported clock sources");
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
"period", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE,
sc, 0, hdspe_sysctl_period, "A",
"Force period of samples per interrupt (32, 64, ... 4096)");
return (bus_generic_attach(dev));
}

View File

@ -227,6 +227,7 @@ struct sc_info {
bus_dmamap_t rmap;
uint32_t period;
uint32_t speed;
uint32_t force_period;
};
#define hdspe_read_1(sc, regno) \