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 29, 2024 +.Dd February 9, 2024 .Dt SND_HDSPE 4 .Os .Sh NAME @@ -64,8 +64,29 @@ .Xr pcm 4 device corresponds to a physical port on the sound card. For ADAT ports, 8 channel, 4 channel and 2 channel formats are supported. +The effective number of ADAT channels is 8 channels at single speed +(32kHz-48kHz), 4 channels at double speed (64kHz-96kHz), and 2 channels at +quad speed (128kHz-192kHz). Depending on sample rate and channel format selected, not all pcm channels can be mapped to ADAT channels and vice versa. +.Sh LOADER TUNABLES +These settings can be entered at the +.Xr loader 8 +prompt or in +.Xr loader.conf 5 . +.Bl -tag -width indent +.It Va hw.hdspe.unified_pcm +If set to 1, all physical ports are combined into one unified pcm device. +When opened in multi-channel audio software, this makes all ports available +at the same time, and fully synchronized. +For resulting channel numbers consult the following table: +.El +.Bl -column "HDSPe RayDAT" "Single Speed" "Double Speed" "Quad Speed" +.Sy "Sound Card" Ta Sy "Single Speed" Ta Sy "Double Speed" Ta Sy "Quad Speed" +.It "" Ta "Play | Rec" Ta "Play | Rec" Ta "Play | Rec" +.It HDSPe AIO Ta " 16 | 14" Ta " 12 | 10" Ta " 10 | 8" +.It HDSPe RayDAT Ta " 36 | 36" Ta " 20 | 20" Ta " 12 | 12" +.El .Sh SYSCTL TUNABLES These settings and informational values can be accessed at runtime with the .Xr sysctl 8 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 @@ -41,6 +41,8 @@ #include +#define HDSPE_MATRIX_MAX 8 + struct hdspe_latency { uint32_t n; uint32_t period; @@ -1007,6 +1009,7 @@ char status[SND_STATUSLEN]; struct sc_pcminfo *scp; const char *buf; + uint32_t pcm_flags; int err; int play, rec; @@ -1025,7 +1028,11 @@ * We don't register interrupt handler with snd_setup_intr * in pcm device. Mark pcm device as MPSAFE manually. */ - pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE); + pcm_flags = pcm_getflags(dev) | SD_F_MPSAFE; + if (hdspe_channel_count(scp->hc->ports, 8) > HDSPE_MATRIX_MAX) + /* Disable vchan conversion, too many channels. */ + pcm_flags |= SD_F_BITPERFECT; + pcm_setflags(dev, pcm_flags); play = (hdspe_channel_play_ports(scp->hc)) ? 1 : 0; rec = (hdspe_channel_rec_ports(scp->hc)) ? 1 : 0; 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 @@ -44,6 +44,14 @@ #include +static bool hdspe_unified_pcm = false; + +static SYSCTL_NODE(_hw, OID_AUTO, hdspe, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, + "PCI HDSPe"); + +SYSCTL_BOOL(_hw_hdspe, OID_AUTO, unified_pcm, CTLFLAG_RWTUN, + &hdspe_unified_pcm, 0, "Combine physical ports in one unified pcm device"); + static struct hdspe_clock_source hdspe_clock_source_table_rd[] = { { "internal", 0 << 1 | 1, HDSPE_STATUS1_CLOCK(15), 0, 0 }, { "word", 0 << 1 | 0, HDSPE_STATUS1_CLOCK( 0), 1 << 24, 1 << 25 }, @@ -78,6 +86,11 @@ { 0, NULL }, }; +static struct hdspe_channel chan_map_aio_uni[] = { + { HDSPE_CHAN_AIO_ALL, "all" }, + { 0, NULL }, +}; + static struct hdspe_channel chan_map_rd[] = { { HDSPE_CHAN_RAY_AES, "aes" }, { HDSPE_CHAN_RAY_SPDIF, "s/pdif" }, @@ -88,6 +101,11 @@ { 0, NULL }, }; +static struct hdspe_channel chan_map_rd_uni[] = { + { HDSPE_CHAN_RAY_ALL, "all" }, + { 0, NULL }, +}; + static void hdspe_intr(void *p) { @@ -538,11 +556,11 @@ switch (rev) { case PCI_REVISION_AIO: sc->type = HDSPE_AIO; - chan_map = chan_map_aio; + chan_map = hdspe_unified_pcm ? chan_map_aio_uni : chan_map_aio; break; case PCI_REVISION_RAYDAT: sc->type = HDSPE_RAYDAT; - chan_map = chan_map_rd; + chan_map = hdspe_unified_pcm ? chan_map_rd_uni : chan_map_rd; break; default: return (ENXIO);