Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107153988
D43252.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D43252.diff
View Options
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 February 13, 2012
+.Dd December 30, 2023
.Dt SND_HDSPE 4
.Os
.Sh NAME
@@ -59,6 +59,45 @@
.It
RME HDSPe RayDAT
.El
+.Sh SYSCTL TUNABLES
+These settings and informational values can be accessed at runtime with the
+.Xr sysctl 8
+command.
+If multiple RME HDSPe sound cards are installed, each device has a separate
+configuration.
+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.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
+audio signals like AES, S/PDIF and ADAT.
+.It Va dev.hdspe.0.clock_preference
+Select a preferred clock source from the clock list.
+HDSPe cards will sync to this clock source when available, but fall back to
+auto-sync with any other digital clock signal they receive.
+Set this to
+.Ql internal
+if the HDSPe card should act as master clock.
+.It Va dev.hdspe.0.clock_source
+Shows the actual clock source in use (read only).
+This differs from what is set as clock preference when in auto-sync mode.
+.It Va dev.hdspe.0.sync_status
+Display the current sync status of all external clock sources.
+Status indications are
+.Ql none
+for no signal at all,
+.Ql lock
+for when a valid signal is present, and
+.Ql sync
+for accurately synchronized signals (required for recording digital
+audio).
+.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.
.Sh SEE ALSO
.Xr sound 4
.Sh HISTORY
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
@@ -519,8 +519,8 @@
}
switch (sc->type) {
- case RAYDAT:
- case AIO:
+ case HDSPE_RAYDAT:
+ case HDSPE_AIO:
period = HDSPE_FREQ_AIO;
break;
default:
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
@@ -32,8 +32,8 @@
#define PCI_REVISION_AIO 212
#define PCI_REVISION_RAYDAT 211
-#define AIO 0
-#define RAYDAT 1
+#define HDSPE_AIO 0
+#define HDSPE_RAYDAT 1
/* Hardware mixer */
#define HDSPE_OUT_ENABLE_BASE 512
@@ -95,15 +95,13 @@
#define HDSP_PhoneGainMinus6dB (HDSP_PhoneGain0)
#define HDSP_PhoneGainMinus12dB 0
-#define HDSPM_statusRegister 0
-#define HDSPM_statusRegister2 192
-
/* Settings */
#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
#define HDSPE_ENABLE (1 << 0)
-#define HDSPM_CLOCK_MODE_MASTER (1 << 4)
/* Interrupts */
#define HDSPE_AUDIO_IRQ_PENDING (1 << 0)
@@ -126,6 +124,23 @@
uint32_t rec;
};
+/* Clock sources */
+#define HDSPE_SETTING_MASTER (1 << 0)
+#define HDSPE_SETTING_CLOCK_MASK 0x1f
+
+#define HDSPE_STATUS1_CLOCK_SHIFT 28
+#define HDSPE_STATUS1_CLOCK_MASK (0x0f << HDSPE_STATUS1_CLOCK_SHIFT)
+#define HDSPE_STATUS1_CLOCK(n) (((n) << HDSPE_STATUS1_CLOCK_SHIFT) & \
+ HDSPE_STATUS1_CLOCK_MASK)
+
+struct hdspe_clock_source {
+ char *name;
+ uint32_t setting;
+ uint32_t status;
+ uint32_t lock_bit;
+ uint32_t sync_bit;
+};
+
static MALLOC_DEFINE(M_HDSPE, "hdspe", "hdspe audio");
/* Channel registers */
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
@@ -31,6 +31,9 @@
* Supported cards: AIO, RayDAT.
*/
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
#include <dev/sound/pcm/sound.h>
#include <dev/sound/pci/hdspe.h>
#include <dev/sound/chip.h>
@@ -40,6 +43,31 @@
#include <mixer_if.h>
+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 },
+ { "aes", 1 << 1 | 0, HDSPE_STATUS1_CLOCK( 1), 1 << 0, 1 << 8 },
+ { "spdif", 2 << 1 | 0, HDSPE_STATUS1_CLOCK( 2), 1 << 1, 1 << 9 },
+ { "adat1", 3 << 1 | 0, HDSPE_STATUS1_CLOCK( 3), 1 << 2, 1 << 10 },
+ { "adat2", 4 << 1 | 0, HDSPE_STATUS1_CLOCK( 4), 1 << 3, 1 << 11 },
+ { "adat3", 5 << 1 | 0, HDSPE_STATUS1_CLOCK( 5), 1 << 4, 1 << 12 },
+ { "adat4", 6 << 1 | 0, HDSPE_STATUS1_CLOCK( 6), 1 << 5, 1 << 13 },
+ { "tco", 9 << 1 | 0, HDSPE_STATUS1_CLOCK( 9), 1 << 26, 1 << 27 },
+ { "sync_in", 10 << 1 | 0, HDSPE_STATUS1_CLOCK(10), 0, 0 },
+ { NULL, 0 << 1 | 0, HDSPE_STATUS1_CLOCK( 0), 0, 0 },
+};
+
+static struct hdspe_clock_source hdspe_clock_source_table_aio[] = {
+ { "internal", 0 << 1 | 1, HDSPE_STATUS1_CLOCK(15), 0, 0 },
+ { "word", 0 << 1 | 0, HDSPE_STATUS1_CLOCK( 0), 1 << 24, 1 << 25 },
+ { "aes", 1 << 1 | 0, HDSPE_STATUS1_CLOCK( 1), 1 << 0, 1 << 8 },
+ { "spdif", 2 << 1 | 0, HDSPE_STATUS1_CLOCK( 2), 1 << 1, 1 << 9 },
+ { "adat", 3 << 1 | 0, HDSPE_STATUS1_CLOCK( 3), 1 << 2, 1 << 10 },
+ { "tco", 9 << 1 | 0, HDSPE_STATUS1_CLOCK( 9), 1 << 26, 1 << 27 },
+ { "sync_in", 10 << 1 | 0, HDSPE_STATUS1_CLOCK(10), 0, 0 },
+ { NULL, 0 << 1 | 0, HDSPE_STATUS1_CLOCK( 0), 0, 0 },
+};
+
static struct hdspe_channel chan_map_aio[] = {
{ 0, 1, "line", 1, 1 },
{ 6, 7, "phone", 1, 0 },
@@ -224,6 +252,169 @@
}
}
+static int
+hdspe_sysctl_clock_preference(SYSCTL_HANDLER_ARGS)
+{
+ struct sc_info *sc;
+ struct hdspe_clock_source *clock_table, *clock;
+ char buf[16] = "invalid";
+ int error;
+ uint32_t setting;
+
+ sc = oidp->oid_arg1;
+
+ /* Select sync ports table for device type. */
+ if (sc->type == HDSPE_AIO)
+ clock_table = hdspe_clock_source_table_aio;
+ else if (sc->type == HDSPE_RAYDAT)
+ clock_table = hdspe_clock_source_table_rd;
+ else
+ return (ENXIO);
+
+ /* Extract preferred clock source from settings register. */
+ setting = sc->settings_register & HDSPE_SETTING_CLOCK_MASK;
+ for (clock = clock_table; clock->name != NULL; ++clock) {
+ if (clock->setting == setting)
+ break;
+ }
+ if (clock->name != NULL)
+ strlcpy(buf, clock->name, sizeof(buf));
+
+ /* Process sysctl string request. */
+ error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ /* Find clock source matching the sysctl string. */
+ for (clock = clock_table; clock->name != NULL; ++clock) {
+ if (strncasecmp(buf, clock->name, sizeof(buf)) == 0)
+ break;
+ }
+
+ /* Set preferred clock source in settings register. */
+ if (clock->name != NULL) {
+ setting = clock->setting & HDSPE_SETTING_CLOCK_MASK;
+ snd_mtxlock(sc->lock);
+ sc->settings_register &= ~HDSPE_SETTING_CLOCK_MASK;
+ sc->settings_register |= setting;
+ hdspe_write_4(sc, HDSPE_SETTINGS_REG, sc->settings_register);
+ snd_mtxunlock(sc->lock);
+ }
+ return (0);
+}
+
+static int
+hdspe_sysctl_clock_source(SYSCTL_HANDLER_ARGS)
+{
+ struct sc_info *sc;
+ struct hdspe_clock_source *clock_table, *clock;
+ char buf[16] = "invalid";
+ uint32_t status;
+
+ sc = oidp->oid_arg1;
+
+ /* Select sync ports table for device type. */
+ if (sc->type == HDSPE_AIO)
+ clock_table = hdspe_clock_source_table_aio;
+ else if (sc->type == HDSPE_RAYDAT)
+ clock_table = hdspe_clock_source_table_rd;
+ else
+ return (ENXIO);
+
+ /* Read current (autosync) clock source from status register. */
+ snd_mtxlock(sc->lock);
+ status = hdspe_read_4(sc, HDSPE_STATUS1_REG);
+ status &= HDSPE_STATUS1_CLOCK_MASK;
+ snd_mtxunlock(sc->lock);
+
+ /* Translate status register value to clock source. */
+ for (clock = clock_table; clock->name != NULL; ++clock) {
+ /* In clock master mode, override with internal clock source. */
+ if (sc->settings_register & HDSPE_SETTING_MASTER) {
+ if (clock->setting & HDSPE_SETTING_MASTER)
+ break;
+ } else if (clock->status == status)
+ break;
+ }
+
+ /* Process sysctl string request. */
+ if (clock->name != NULL)
+ strlcpy(buf, clock->name, sizeof(buf));
+ return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
+}
+
+static int
+hdspe_sysctl_clock_list(SYSCTL_HANDLER_ARGS)
+{
+ struct sc_info *sc;
+ struct hdspe_clock_source *clock_table, *clock;
+ char buf[256];
+ int n;
+
+ sc = oidp->oid_arg1;
+ n = 0;
+
+ /* Select clock source table for device type. */
+ if (sc->type == HDSPE_AIO)
+ clock_table = hdspe_clock_source_table_aio;
+ else if (sc->type == HDSPE_RAYDAT)
+ clock_table = hdspe_clock_source_table_rd;
+ else
+ return (ENXIO);
+
+ /* List available clock sources. */
+ buf[0] = 0;
+ for (clock = clock_table; clock->name != NULL; ++clock) {
+ if (n > 0)
+ n += strlcpy(buf + n, ",", sizeof(buf) - n);
+ n += strlcpy(buf + n, clock->name, sizeof(buf) - n);
+ }
+ return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
+}
+
+static int
+hdspe_sysctl_sync_status(SYSCTL_HANDLER_ARGS)
+{
+ struct sc_info *sc;
+ struct hdspe_clock_source *clock_table, *clock;
+ char buf[256];
+ char *state;
+ int n;
+ uint32_t status;
+
+ sc = oidp->oid_arg1;
+ n = 0;
+
+ /* Select sync ports table for device type. */
+ if (sc->type == HDSPE_AIO)
+ clock_table = hdspe_clock_source_table_aio;
+ else if (sc->type == HDSPE_RAYDAT)
+ clock_table = hdspe_clock_source_table_rd;
+ else
+ return (ENXIO);
+
+ /* Read current lock and sync bits from status register. */
+ snd_mtxlock(sc->lock);
+ status = hdspe_read_4(sc, HDSPE_STATUS1_REG);
+ snd_mtxunlock(sc->lock);
+
+ /* List clock sources with lock and sync state. */
+ for (clock = clock_table; clock->name != NULL; ++clock) {
+ if (clock->sync_bit != 0) {
+ if (n > 0)
+ n += strlcpy(buf + n, ",", sizeof(buf) - n);
+ state = "none";
+ if ((clock->sync_bit & status) != 0)
+ state = "sync";
+ else if ((clock->lock_bit & status) != 0)
+ state = "lock";
+ n += snprintf(buf + n, sizeof(buf) - n, "%s(%s)",
+ clock->name, state);
+ }
+ }
+ return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
+}
+
static int
hdspe_probe(device_t dev)
{
@@ -250,9 +441,6 @@
{
long long period;
- /* Set defaults. */
- sc->ctrl_register |= HDSPM_CLOCK_MODE_MASTER;
-
/* Set latency. */
sc->period = 32;
sc->ctrl_register = hdspe_encode_latency(7);
@@ -264,8 +452,8 @@
hdspe_write_4(sc, HDSPE_CONTROL_REG, sc->ctrl_register);
switch (sc->type) {
- case RAYDAT:
- case AIO:
+ case HDSPE_RAYDAT:
+ case HDSPE_AIO:
period = HDSPE_FREQ_AIO;
break;
default:
@@ -305,11 +493,11 @@
rev = pci_get_revid(dev);
switch (rev) {
case PCI_REVISION_AIO:
- sc->type = AIO;
+ sc->type = HDSPE_AIO;
chan_map = chan_map_aio;
break;
case PCI_REVISION_RAYDAT:
- sc->type = RAYDAT;
+ sc->type = HDSPE_RAYDAT;
chan_map = chan_map_rd;
break;
default:
@@ -336,6 +524,30 @@
hdspe_map_dmabuf(sc);
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "sync_status", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sc, 0, hdspe_sysctl_sync_status, "A",
+ "List clock source signal lock and sync status");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "clock_source", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sc, 0, hdspe_sysctl_clock_source, "A",
+ "Currently effective clock source");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "clock_preference", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ sc, 0, hdspe_sysctl_clock_preference, "A",
+ "Set 'internal' (master) or preferred autosync clock source");
+
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "clock_list", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sc, 0, hdspe_sysctl_clock_list, "A",
+ "List of supported clock sources");
+
return (bus_generic_attach(dev));
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Jan 11, 11:00 PM (15 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15758671
Default Alt Text
D43252.diff (11 KB)
Attached To
Mode
D43252: snd_hdspe(4): Add sysctl settings for clock source.
Attached
Detach File
Event Timeline
Log In to Comment