[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