[PATCH] es137x s/pdif output

Jon Noack noackjr at alumni.rice.edu
Sun Feb 8 04:00:30 PST 2004


The discussion last month about 4-channel output prompted me to get off 
my butt and enable S/PDIF output on the CT5880-E.  I found this white 
paper (http://www.corbac.com/Data/Misc/es1373.ps.gz) to be invaluable. 
I also need to credit the sysctl stuff from /sys/dev/sound/pci/via8233.c 
as most of my patch was taken verbatim from there.

Setting hw.snd.pcmX.spdif_enabled=1:
1) ENABLE_SPDIF output
2) Set to SPDIF_OUT instead of SPDIF_THRU
3) Mute analog input to get clean digital out (with RECEN_B)

Setting it back to 0 just reverts these 3 steps.

Several things:
1) This is currently only enabled for the CT5880-E.  Other es137x-based 
cards support S/PDIF and this should be enabled for them also -- I just 
didn't know which ones.
2) It's probably not necessary to toggle SPDIF_OUT/SPDIF_THRU every time.
3) Enabling this causes a degradation in the sound coming over the 
analog outputs.  I don't see anything to help clean this up.  Perhaps we 
should just mute these (how would one do this?).
4) Master volume control has no effect (although individual pcm stream 
volume is properly handled).
5) I have no idea if my coding style or the functions used were correct. 
  A review by someone in the know would be much appreciated.

I've been using this for over an hour with several toggles of the 
spdif_enabled sysctl; S/PDIF output was correctly enabled and disabled 
each time.  It sounds *sooo* much better over my surround system :).

I feel rather silly for having bought the 4Front drivers a couple years 
ago because the FreeBSD driver lacked this very functionality -- such a 
simple change...

Jon Noack
-------------- next part --------------
diff -ruN es137x.c.orig es137x.c
--- es137x.c.orig	Sun Feb  8 04:23:36 2004
+++ es137x.c	Sun Feb  8 04:56:25 2004
@@ -831,6 +831,59 @@
 	}
 }
 
+static int es1371x_spdif_en;
+
+static int
+sysctl_es1371x_spdif_enable(SYSCTL_HANDLER_ARGS)
+{
+	struct es_info *es;
+	device_t dev;
+	int err, new_en, r;
+
+	new_en = es1371x_spdif_en;
+	err = sysctl_handle_int(oidp, &new_en, sizeof(new_en), req);
+	if (err || req->newptr == NULL)
+		return err;
+
+	if (new_en < 0 || new_en > 1)
+		return EINVAL;
+	es1371x_spdif_en = new_en;
+
+	dev = oidp->oid_arg1;
+	es = pcm_getdevinfo(dev);
+	r = bus_space_read_4(es->st, es->sh, ES1370_REG_STATUS);
+	if (new_en) {
+		r |= ENABLE_SPDIF;
+		es->ctrl |= SPDIFEN_B;
+		es->ctrl |= RECEN_B;
+	} else {
+		r &= ~ENABLE_SPDIF;
+		es->ctrl &= ~SPDIFEN_B;
+		es->ctrl &= ~RECEN_B;
+	}
+	bus_space_write_4(es->st, es->sh, ES1370_REG_CONTROL, es->ctrl);
+	bus_space_write_4(es->st, es->sh, ES1370_REG_STATUS, r);
+	return 0;
+}
+
+static void
+es_init_sysctls(device_t dev)
+{
+	struct es_info *es;
+	int r;
+
+	es = pcm_getdevinfo(dev);
+	r = bus_space_read_4(es->st, es->sh, ES1370_REG_STATUS);
+	es1371x_spdif_en = (r & ENABLE_SPDIF) ? 1 : 0;
+
+	SYSCTL_ADD_PROC(snd_sysctl_tree(dev),
+			SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
+			OID_AUTO, "spdif_enabled",
+			CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev),
+			sysctl_es1371x_spdif_enable, "I",
+			"Enable S/PDIF output on primary playback channel");
+}
+
 static int
 es_pci_attach(device_t dev)
 {
@@ -931,6 +984,11 @@
 	if (pcm_register(dev, es, 1, 1)) goto bad;
 	pcm_addchan(dev, PCMDIR_REC, ct, es);
 	pcm_addchan(dev, PCMDIR_PLAY, ct, es);
+
+	/* Only initialize for the CT5880-E */
+	if (pci_get_devid(dev) == CT5880_PCI_ID || pci_get_revid(dev) == CT5880REV_CT5880_E)
+		es_init_sysctls(dev);
+
 	pcm_setstatus(dev, status);
 
 	return 0;
diff -ruN es137x.h.orig es137x.h
--- es137x.h.orig	Sun Feb  8 04:23:40 2004
+++ es137x.h	Sun Feb  8 04:50:19 2004
@@ -167,6 +167,17 @@
 #define ES1371_SRC_RAM_DATAI(i) (((i)>>0)&0xffff)	/* current value of the sample rate converter */
 
 /*
+ * S/PDIF specific
+ */
+
+/* Use ES1370_REG_CONTROL */
+#define RECEN_B			0x08000000	/* Used to control mixing of analog with digital data */
+#define SPDIFEN_B		0x04000000	/* Reset to switch digital output mux to "THRU" mode */
+/* Use ES1370_REG_STATUS */
+#define ENABLE_SPDIF		0x00040000	/* Used to enable the S/PDIF circuitry */
+#define TEST_SPDIF		0x00020000	/* Used to put the S/PDIF module in "test mode" */
+
+/*
  *  Sample rate converter addresses
  */
 


More information about the freebsd-multimedia mailing list