This patch enables the SPDIF input of the Realtek ALC650 chip which is an AC97 compatible chip.
It also adds some data into the proc file system ac97 /proc/asound/card0/ac97#0 file so one can see if the SPDIF is locked or not.
I can now record AC3 non-audio data from an Optical SPDIF socket on my Motherboard.
This only works for ALC650 Rev.E or above, so I guess I should really check for that.
Cheers James
diff -ur linux-2.6.0-test4/include/sound/ac97_codec.h
/usr/src/linux-beta/include/sound/ac97_codec.h
--- linux-2.6.0-test4/include/sound/ac97_codec.h 2003-08-23 00:56:25.000000000
+0100
+++ /usr/src/linux-beta/include/sound/ac97_codec.h 2003-08-30 16:19:46.000000000
+0100
@@ -214,11 +214,50 @@
#define AC97_CXR_SPDIF_AC3 0x2
/* specific - ALC */
+#define AC97_ALC650_SPDIF_INPUT_STATUS1 0x60
+/* S/PDIF input status 1 bit defines */
+#define AC97_ALC650_PRO 0x0001 /* Professional status */
+#define AC97_ALC650_NAUDIO 0x0002 /* Non audio stream */
+#define AC97_ALC650_COPY 0x0004 /* Copyright status */
+#define AC97_ALC650_PRE 0x0038 /* Preemphasis status */
+#define AC97_ALC650_PRE_SHIFT 3
+#define AC97_ALC650_MODE 0x00C0 /* Preemphasis status */
+#define AC97_ALC650_MODE_SHIFT 6
+#define AC97_ALC650_CC_MASK 0x7f00 /* Category Code mask */
+#define AC97_ALC650_CC_SHIFT 8
+#define AC97_ALC650_L 0x8000 /* Generation Level status */
+
+#define AC97_ALC650_SPDIF_INPUT_STATUS2 0x62
+/* S/PDIF input status 2 bit defines */
+#define AC97_ALC650_SOUCE_MASK 0x000f /* Source number */
+#define AC97_ALC650_CHANNEL_MASK 0x00f0 /* Channel number */
+#define AC97_ALC650_CHANNEL_SHIFT 4
+#define AC97_ALC650_SPSR_MASK 0x0f00 /* S/PDIF Sample Rate bits */
+#define AC97_ALC650_SPSR_SHIFT 8
+#define AC97_ALC650_SPSR_44K 0x0000 /* Use 44.1kHz Sample rate */
+#define AC97_ALC650_SPSR_48K 0x0200 /* Use 48kHz Sample rate */
+#define AC97_ALC650_SPSR_32K 0x0300 /* Use 32kHz Sample rate */
+#define AC97_ALC650_CLOCK_ACCURACY 0x3000 /* Clock accuracy */
+#define AC97_ALC650_CLOCK_SHIFT 12
+#define AC97_ALC650_CLOCK_LOCK 0x4000 /* Clock locked status */
+#define AC97_ALC650_V 0x8000 /* Validity status */
+
#define AC97_ALC650_SURR_DAC_VOL 0x64
#define AC97_ALC650_LFE_DAC_VOL 0x66
+#define AC97_ALC650_UNKNOWN1 0x68
#define AC97_ALC650_MULTICH 0x6a
+#define AC97_ALC650_UNKNOWN2 0x6c
+#define AC97_ALC650_REVISION 0x6e
+#define AC97_ALC650_UNKNOWN3 0x70
+#define AC97_ALC650_UNKNOWN4 0x72
+#define AC97_ALC650_MISC 0x74
+#define AC97_ALC650_GPIO_SETUP 0x76
+#define AC97_ALC650_GPIO_STATUS 0x78
#define AC97_ALC650_CLOCK 0x7a
+
+
+
/* specific - Yamaha YMF753 */
#define AC97_YMF753_DIT_CTRL2 0x66 /* DIT Control 2 */
#define AC97_YMF753_3D_MODE_SEL 0x68 /* 3D Mode Select */
diff -ur linux-2.6.0-test4/sound/pci/ac97/ac97_patch.c
/usr/src/linux-beta/sound/pci/ac97/ac97_patch.c
--- linux-2.6.0-test4/sound/pci/ac97/ac97_patch.c 2003-08-23 01:00:10.000000000
+0100
+++ /usr/src/linux-beta/sound/pci/ac97/ac97_patch.c 2003-08-30 17:35:31.488713520
+0100
@@ -874,8 +874,10 @@
val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS);
if (val & AC97_EA_SPCV)
spdif = 1;
-
if (spdif) {
+ //enable AC97_ALC650_GPIO_SETUP, AC97_ALC650_CLOCK for R/W
+ snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_STATUS,
+ snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS) | 0x8000);
/* enable spdif in */
snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK,
snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x03);
@@ -891,18 +893,18 @@
int mic_off;
mic_off = snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10);
/* GPIO0 direction */
- val = snd_ac97_read(ac97, 0x76);
+ val = snd_ac97_read(ac97, AC97_ALC650_GPIO_SETUP);
if (mic_off)
val &= ~0x01;
else
val |= 0x01;
- snd_ac97_write_cache(ac97, 0x76, val);
- val = snd_ac97_read(ac97, 0x78);
+ snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_SETUP, val);
+ val = snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS);
if (mic_off)
val &= ~0x100;
else
val = val | 0x100;
- snd_ac97_write_cache(ac97, 0x78, val);
+ snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_STATUS, val);
}
/* full DAC volume */
diff -ur linux-2.6.0-test4/sound/pci/ac97/ac97_proc.c
/usr/src/linux-beta/sound/pci/ac97/ac97_proc.c
--- linux-2.6.0-test4/sound/pci/ac97/ac97_proc.c 2003-08-23 01:03:01.000000000
+0100
+++ /usr/src/linux-beta/sound/pci/ac97/ac97_proc.c 2003-08-30 16:55:06.000000000
+0100
@@ -38,7 +38,7 @@
{
char name[64];
unsigned int id;
- unsigned short val, tmp, ext, mext;
+ unsigned short val, tmp, ext, mext, spdif_in;
static const char *spdif_slots[4] = { " SPDIF=3/4", " SPDIF=7/8", "
SPDIF=6/9", " SPDIF=res" };
static const char *spdif_rates[4] = { " Rate=44.1kHz", " Rate=res", "
Rate=48kHz", " Rate=32kHz" };
static const char *spdif_rates_cs4205[4] = { " Rate=48kHz", " Rate=44.1kHz", "
Rate=res", " Rate=res" };
@@ -151,7 +151,7 @@
snd_iprintf(buffer, "SPDIF Control :%s%s%s%s Category=0x%x
Generation=%i%s%s%s\n",
val & AC97_SC_PRO ? " PRO" : " Consumer",
val & AC97_SC_NAUDIO ? " Non-audio" : " PCM",
- val & AC97_SC_COPY ? " Copyright" : "",
+ val & AC97_SC_COPY ? "" : " Copyright",
val & AC97_SC_PRE ? " Preemph50/15" : "",
(val & AC97_SC_CC_MASK) >> AC97_SC_CC_SHIFT,
(val & AC97_SC_L) >> 11,
@@ -165,6 +165,29 @@
(val & AC97_SC_V ? " Enabled" : "") :
(val & AC97_SC_V ? " Validity" : ""));
}
+ spdif_in = snd_ac97_read(ac97, AC97_ALC650_CLOCK);
+ if (spdif_in & 0x01) {
+ val = snd_ac97_read(ac97, AC97_ALC650_SPDIF_INPUT_STATUS2);
+ if (val & AC97_ALC650_CLOCK_LOCK) {
+ val = snd_ac97_read(ac97, AC97_ALC650_SPDIF_INPUT_STATUS1);
+ snd_iprintf(buffer, "SPDIF In Status :%s%s%s%s Category=0x%x
Generation=%i",
+ val & AC97_ALC650_PRO ? " PRO" : " Consumer",
+ val & AC97_ALC650_NAUDIO ? " Non-audio" : " PCM",
+ val & AC97_ALC650_COPY ? "" : " Copyright",
+ val & AC97_ALC650_PRE ? " Preemph50/15" : "",
+ (val & AC97_ALC650_CC_MASK) >> AC97_ALC650_CC_SHIFT,
+ (val & AC97_ALC650_L) >> 15);
+ val = snd_ac97_read(ac97, AC97_ALC650_SPDIF_INPUT_STATUS2);
+ snd_iprintf(buffer, "%s Accuracy=%i%s%s\n",
+ spdif_rates[(val & AC97_ALC650_SPSR_MASK) >>
AC97_ALC650_SPSR_SHIFT],
+ (val & AC97_ALC650_CLOCK_ACCURACY) >> AC97_ALC650_CLOCK_SHIFT,
+ (val & AC97_ALC650_CLOCK_LOCK ? " Locked" : " Unlocked"),
+ (val & AC97_ALC650_V ? " Validity?" : ""));
+ } else {
+ snd_iprintf(buffer, "SPDIF In Status : Not Locked\n");
+ }
+ }
+
__modem:
mext = snd_ac97_read(ac97, AC97_EXTENDED_MID);
