kern/68594: [PATCH] enable S/PDIF output for es137x sound cards

Jonathan Noack noackj at concordiacrusaders.org
Fri Jul 2 01:21:30 PDT 2004


>Number:         68594
>Category:       kern
>Synopsis:       [PATCH] enable S/PDIF output for es137x sound cards
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jul 02 08:20:22 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator:     Jonathan Noack
>Release:        FreeBSD 5.2-CURRENT i386
>Organization:
Concordia Lutheran High School
>Environment:
System: FreeBSD compgeek.noacks.org 5.2-CURRENT FreeBSD 5.2-CURRENT #11: Wed Jun 30 19:53:45 CDT 2004 noackjr at compgeek.noacks.org:/usr/obj/usr/src/sys/COMPGEEK i386
>Description:
	Filing PR so this doesn't get lost.  I have been using this patch
	for four months now with no problems (other than generic pcm
	issues such as the locking...).  See freebsd-multimedia archive
	for original discussion:
	http://docs.freebsd.org/cgi/mid.cgi?402624D7.4060009

	This code was adapted from the via8233 driver.  The es1373 white
	paper at http://www.corbac.com/Data/Misc/es1373.ps.gz was also
	invaluable.

	I added a hw.snd.pcmX.spdif_enabled sysctl to enable/disable the
	S/PDIF support.  Enabling this sysctl does three things:
	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)

	Disabling the sysctl just reverts these three steps.

	Things to ponder/shake_your_fist_at_the_world_over:
	1) Mathew Kanner said he was working on revamping the pcm(4) man
	   page.  As a result, there is no man page update with this PR.
	2) This may not work for all es137x sound cards.  I do not know
	   what will happen if S/PDIF is enabled on a card that doesn't
	   support it.  Most sources say only revision 4+ cards support
	   S/PDIF, but some disagree with this.  *shrug*
	3) Enabling S/PDIF causes a degradation in the quality of the
	   analog sound outputs.  I believe this degradation is caused by
	   the sound card outputting both the analog and digital signals
	   to the same analog output plug.  This may be due to some
	   versions of the card not having a separate digital out plug
	   (the line out serves as both the analog and digital out).  If
	   so, it may be necessary to mute the analog portion in order to
	   get a clean digital signal on these cards.
	4) Master volume control has no effect (although individual pcm
	   stream volume is properly handled.
>How-To-Repeat:
	N/A
>Fix:
	See patch below.

--- es137x.diff begins here ---
Index: es137x.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/sound/pci/es137x.c,v
retrieving revision 1.50
diff -u -r1.50 es137x.c
--- es137x.c	17 Mar 2004 17:50:44 -0000	1.50
+++ es137x.c	25 May 2004 12:35:15 -0000
@@ -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,9 @@
 	if (pcm_register(dev, es, 1, 1)) goto bad;
 	pcm_addchan(dev, PCMDIR_REC, ct, es);
 	pcm_addchan(dev, PCMDIR_PLAY, ct, es);
+
+	es_init_sysctls(dev);
+
 	pcm_setstatus(dev, status);
 
 	return 0;
Index: es137x.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/sound/pci/es137x.h,v
retrieving revision 1.4
diff -u -r1.4 es137x.h
--- es137x.h	5 Apr 2000 00:38:00 -0000	1.4
+++ es137x.h	25 May 2004 12:35:15 -0000
@@ -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
  */
 
--- es137x.diff ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list