Alsa-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868
@ 2011-05-30 13:22 Harry Butterworth
  2011-06-03 15:44 ` Takashi Iwai
  2011-06-05  4:35 ` Marshall DeBerry
  0 siblings, 2 replies; 11+ messages in thread
From: Harry Butterworth @ 2011-05-30 13:22 UTC (permalink / raw)
  To: Alsa-devel

[-- Attachment #1: Type: text/plain, Size: 1147 bytes --]

Hello folks,

    I bought an X-Fi Titanium HD thinking it would work with the ctxfi
driver but it is a new card and has a few differences from the earlier
cards.  Creative technical support have been quite helpful in
answering my questions.  This email is a heads-up to let you know that
I'm doing some work on the driver.

    I'm not finished yet.  In particular the PLL initialization still
does not work reliably, the capture source selection is a bit broken
and one of the ADC chips is being driven out-of-spec when the card is
run at 192kHz.

    I have attached the current state of my changes which are enough
to get the Titanium HD card working but the patch shouldn't be applied
because my hack at the PLL code and a couple of other bits may break
existing cards.  I have been working against the ALSA 1.0.24 release
so this is a patch against 1.0.24.

    I'm waiting for creative to answer my questions about the PLL
initialization and correct setup for 196kHz operation.  Once I get the
answers I'll try to fix the issues and submit a cleaner patch.

    Comments on the current version are welcome.

Harry

[-- Attachment #2: Titanium-HD --]
[-- Type: application/octet-stream, Size: 36520 bytes --]

diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/ct20k2reg.h
--- a/alsa-kernel/pci/ctxfi/ct20k2reg.h	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ct20k2reg.h	Mon May 30 20:29:07 2011 +0800
@@ -55,6 +55,7 @@
 /* GPIO Registers */
 #define GPIO_DATA           0x1B7020
 #define GPIO_CTRL           0x1B7024
+#define GPIO_EXT_DATA       0x1B70A0
 
 /* Virtual memory registers */
 #define VMEM_PTPAL          0x1C6300 /* 0x1C6300 + (16 * Chn) */
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/ctatc.c
--- a/alsa-kernel/pci/ctxfi/ctatc.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctatc.c	Mon May 30 20:29:07 2011 +0800
@@ -30,7 +30,6 @@
 #include <sound/asoundef.h>
 
 #define MONO_SUM_SCALE	0x19a8	/* 2^(-0.5) in 14-bit floating format */
-#define DAIONUM		7
 #define MAX_MULTI_CHN	8
 
 #define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \
@@ -53,6 +52,8 @@
 static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = {
 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760,
 		      "SB0760", CTSB0760),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270,
+		      "SB1270", CTSB1270),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801,
 		      "SB0880", CTSB0880),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802,
@@ -75,6 +76,7 @@
 	[CTSB0760]	= "SB076x",
 	[CTHENDRIX]	= "Hendrix",
 	[CTSB0880]	= "SB0880",
+	[CTSB1270]      = "SB1270",
 	[CT20K2_UNKNOWN] = "Unknown",
 };
 
@@ -459,12 +461,12 @@
 				apcm->substream->runtime->rate);
 	*n_srcc = 0;
 
-	if (1 == atc->msr) {
+	if (1 == atc->msr) { /* FIXME: do we really need SRC here if pitch==1 */
 		*n_srcc = apcm->substream->runtime->channels;
 		conf[0].pitch = pitch;
 		conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1;
 		conf[0].vo = 1;
-	} else if (2 == atc->msr) {
+	} else if (2 <= atc->msr) {
 		if (0x8000000 < pitch) {
 			/* Need two-stage SRCs, SRCIMPs and
 			 * AMIXERs for converting format */
@@ -977,6 +979,55 @@
 	return hw->have_digit_io_switch(hw);
 }
 
+static int atc_have_dedicated_mic(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->have_dedicated_mic(hw);
+}
+
+static int atc_have_output_switch(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->have_output_switch(hw);
+}
+
+static int atc_output_switch_get(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->output_switch_get(hw);
+}
+
+static int atc_output_switch_put(struct ct_atc *atc,int position)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->output_switch_put(hw,position);
+}
+
+static int atc_have_mic_source_switch(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->have_mic_source_switch(hw);
+}
+
+static int atc_mic_source_switch_get(struct ct_atc *atc)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->mic_source_switch_get(hw);
+}
+
+static int atc_mic_source_switch_put(struct ct_atc *atc,int position)
+{
+	struct hw *hw = atc->hw;
+
+	return hw->mic_source_switch_put(hw,position);
+}
+
 static int atc_select_digit_io(struct ct_atc *atc)
 {
 	struct hw *hw = atc->hw;
@@ -1045,6 +1096,11 @@
 	return atc_daio_unmute(atc, state, LINEIM);
 }
 
+static int atc_mic_unmute(struct ct_atc *atc, unsigned char state)
+{
+	return atc_daio_unmute(atc, state, MIC);
+}
+
 static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state)
 {
 	return atc_daio_unmute(atc, state, SPDIFOO);
@@ -1331,17 +1387,20 @@
 	struct srcimp_mgr *srcimp_mgr;
 	struct sum_desc sum_dsc = {0};
 	struct sum_mgr *sum_mgr;
-	int err, i;
+	int err, i, num_srcs, num_daios;
 
-	atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL);
+	num_daios = ( ( atc->model == CTSB1270 ) ? 8 : 7 );
+	num_srcs = ( ( atc->model == CTSB1270 ) ? 6 : 4 );
+
+	atc->daios = kzalloc(sizeof(void *)*num_daios, GFP_KERNEL);
 	if (!atc->daios)
 		return -ENOMEM;
 
-	atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+	atc->srcs = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL);
 	if (!atc->srcs)
 		return -ENOMEM;
 
-	atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
+	atc->srcimps = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL);
 	if (!atc->srcimps)
 		return -ENOMEM;
 
@@ -1351,8 +1410,9 @@
 
 	daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
 	da_desc.msr = atc->msr;
-	for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) {
-		da_desc.type = i;
+	for (i = 0, atc->n_daio = 0; i < num_daios; i++) {
+		da_desc.type = (atc->model != CTSB073X) ? i :
+			     ( ( i == SPDIFIO ) ? SPDIFI1 : i );
 		err = daio_mgr->get_daio(daio_mgr, &da_desc,
 					(struct daio **)&atc->daios[i]);
 		if (err) {
@@ -1362,23 +1422,12 @@
 		}
 		atc->n_daio++;
 	}
-	if (atc->model == CTSB073X)
-		da_desc.type = SPDIFI1;
-	else
-		da_desc.type = SPDIFIO;
-	err = daio_mgr->get_daio(daio_mgr, &da_desc,
-				(struct daio **)&atc->daios[i]);
-	if (err) {
-		printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n");
-		return err;
-	}
-	atc->n_daio++;
 
 	src_mgr = atc->rsc_mgrs[SRC];
 	src_dsc.multi = 1;
 	src_dsc.msr = atc->msr;
 	src_dsc.mode = ARCRW;
-	for (i = 0, atc->n_src = 0; i < (2*2); i++) {
+	for (i = 0, atc->n_src = 0; i < num_srcs; i++) {
 		err = src_mgr->get_src(src_mgr, &src_dsc,
 					(struct src **)&atc->srcs[i]);
 		if (err)
@@ -1388,8 +1437,8 @@
 	}
 
 	srcimp_mgr = atc->rsc_mgrs[SRCIMP];
-	srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */
-	for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) {
+	srcimp_dsc.msr = 8;
+	for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) {
 		err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
 					(struct srcimp **)&atc->srcimps[i]);
 		if (err)
@@ -1397,15 +1446,6 @@
 
 		atc->n_srcimp++;
 	}
-	srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */
-	for (i = 0; i < (2*1); i++) {
-		err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
-				(struct srcimp **)&atc->srcimps[2*1+i]);
-		if (err)
-			return err;
-
-		atc->n_srcimp++;
-	}
 
 	sum_mgr = atc->rsc_mgrs[SUM];
 	sum_dsc.msr = atc->msr;
@@ -1488,6 +1528,18 @@
 	src = atc->srcs[3];
 	mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
 
+	if(atc->model == CTSB1270){
+	        /* Titanium HD has a dedicated ADC for the Mic. */
+		dai = container_of(atc->daios[MIC], struct dai, daio);
+		atc_connect_dai(atc->rsc_mgrs[SRC], dai,
+			(struct src **)&atc->srcs[4],
+			(struct srcimp **)&atc->srcimps[4]);
+		src = atc->srcs[4];
+		mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc);
+		src = atc->srcs[5];
+		mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc);
+	}
+
 	dai = container_of(atc->daios[SPDIFIO], struct dai, daio);
 	atc_connect_dai(atc->rsc_mgrs[SRC], dai,
 			(struct src **)&atc->srcs[0],
@@ -1606,12 +1658,20 @@
 	.line_clfe_unmute = atc_line_clfe_unmute,
 	.line_rear_unmute = atc_line_rear_unmute,
 	.line_in_unmute = atc_line_in_unmute,
+	.mic_unmute = atc_mic_unmute,
 	.spdif_out_unmute = atc_spdif_out_unmute,
 	.spdif_in_unmute = atc_spdif_in_unmute,
 	.spdif_out_get_status = atc_spdif_out_get_status,
 	.spdif_out_set_status = atc_spdif_out_set_status,
 	.spdif_out_passthru = atc_spdif_out_passthru,
 	.have_digit_io_switch = atc_have_digit_io_switch,
+	.have_dedicated_mic = atc_have_dedicated_mic,
+	.have_output_switch = atc_have_output_switch,
+	.output_switch_get = atc_output_switch_get,
+	.output_switch_put = atc_output_switch_put,
+	.have_mic_source_switch = atc_have_mic_source_switch,
+	.mic_source_switch_get = atc_mic_source_switch_get,
+	.mic_source_switch_put = atc_mic_source_switch_put,
 #ifdef CONFIG_PM
 	.suspend = atc_suspend,
 	.resume = atc_resume,
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/ctatc.h
--- a/alsa-kernel/pci/ctxfi/ctatc.h	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctatc.h	Mon May 30 20:29:07 2011 +0800
@@ -115,12 +115,20 @@
 	int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*line_in_unmute)(struct ct_atc *atc, unsigned char state);
+	int (*mic_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state);
 	int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
 	int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
 	int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
 	int (*have_digit_io_switch)(struct ct_atc *atc);
+	int (*have_dedicated_mic)(struct ct_atc *atc);
+	int (*have_output_switch)(struct ct_atc *atc);
+	int (*output_switch_get)(struct ct_atc *atc);
+	int (*output_switch_put)(struct ct_atc *atc,int position);
+	int (*have_mic_source_switch)(struct ct_atc *atc);
+	int (*mic_source_switch_get)(struct ct_atc *atc);
+	int (*mic_source_switch_put)(struct ct_atc *atc,int position);
 
 	/* Don't touch! Used for internal object. */
 	void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/ctdaio.c
--- a/alsa-kernel/pci/ctxfi/ctdaio.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctdaio.c	Mon May 30 20:29:07 2011 +0800
@@ -22,20 +22,9 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 
-#define DAIO_RESOURCE_NUM	NUM_DAIOTYP
 #define DAIO_OUT_MAX		SPDIFOO
 
-union daio_usage {
-	struct {
-		unsigned short lineo1:1;
-		unsigned short lineo2:1;
-		unsigned short lineo3:1;
-		unsigned short lineo4:1;
-		unsigned short spdifoo:1;
-		unsigned short lineim:1;
-		unsigned short spdifio:1;
-		unsigned short spdifi1:1;
-	} bf;
+struct daio_usage {
 	unsigned short data;
 };
 
@@ -61,6 +50,7 @@
 	[LINEO3] = {.left = 0x50, .right = 0x51},
 	[LINEO4] = {.left = 0x70, .right = 0x71},
 	[LINEIM] = {.left = 0x45, .right = 0xc5},
+	[MIC]	 = {.left = 0x55, .right = 0xd5},
 	[SPDIFOO] = {.left = 0x00, .right = 0x01},
 	[SPDIFIO] = {.left = 0x05, .right = 0x85},
 };
@@ -138,6 +128,7 @@
 		case LINEO3:	return 5;
 		case LINEO4:	return 6;
 		case LINEIM:	return 4;
+		case MIC:	return 5;
 		default:	return -EINVAL;
 		}
 	default:
@@ -517,17 +508,17 @@
 
 static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
 {
-	if (((union daio_usage *)mgr->rscs)->data & (0x1 << type))
+	if (((struct daio_usage *)mgr->rscs)->data & (0x1 << type))
 		return -ENOENT;
 
-	((union daio_usage *)mgr->rscs)->data |= (0x1 << type);
+	((struct daio_usage *)mgr->rscs)->data |= (0x1 << type);
 
 	return 0;
 }
 
 static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
 {
-	((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
+	((struct daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
 
 	return 0;
 }
@@ -710,7 +701,7 @@
 	if (!daio_mgr)
 		return -ENOMEM;
 
-	err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw);
+	err = rsc_mgr_init(&daio_mgr->mgr, DAIO, NUM_DAIOTYP, hw);
 	if (err)
 		goto error1;
 
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/ctdaio.h
--- a/alsa-kernel/pci/ctxfi/ctdaio.h	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctdaio.h	Mon May 30 20:29:07 2011 +0800
@@ -33,6 +33,7 @@
 	SPDIFOO,	/* S/PDIF Out (Flexijack/Optical) */
 	LINEIM,
 	SPDIFIO,	/* S/PDIF In (Flexijack/Optical) on the card */
+	MIC,		/* Dedicated mic on Titanium HD */
 	SPDIFI1,	/* S/PDIF In on internal Drive Bay */
 	NUM_DAIOTYP
 };
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/cthardware.h
--- a/alsa-kernel/pci/ctxfi/cthardware.h	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/cthardware.h	Mon May 30 20:29:07 2011 +0800
@@ -39,6 +39,7 @@
 	CT20K2_MODEL_FIRST = CTSB0760,
 	CTHENDRIX,
 	CTSB0880,
+	CTSB1270,
 	CT20K2_UNKNOWN,
 	NUM_CTCARDS		/* This should always be the last */
 };
@@ -71,6 +72,13 @@
 	int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source);
 	int (*select_adc_source)(struct hw *hw, enum ADCSRC source);
 	int (*have_digit_io_switch)(struct hw *hw);
+	int (*have_dedicated_mic)(struct hw *hw);
+	int (*have_output_switch)(struct hw *hw);
+	int (*output_switch_get)(struct hw *hw);
+	int (*output_switch_put)(struct hw *hw,int position);
+	int (*have_mic_source_switch)(struct hw *hw);
+	int (*mic_source_switch_get)(struct hw *hw);
+	int (*mic_source_switch_put)(struct hw *hw,int position);
 
 	/* SRC operations */
 	int (*src_rsc_get_ctrl_blk)(void **rblk);
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/cthw20k1.c
--- a/alsa-kernel/pci/ctxfi/cthw20k1.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/cthw20k1.c	Mon May 30 20:29:07 2011 +0800
@@ -1783,6 +1783,21 @@
 	return !(hw->model == CTSB073X || hw->model == CTUAA);
 }
 
+static int hw_have_dedicated_mic(struct hw *hw)
+{
+	return 0;
+}
+
+static int hw_have_output_switch(struct hw *hw)
+{
+	return 0;
+}
+
+static int hw_have_mic_source_switch(struct hw *hw)
+{
+	return 0;
+}
+
 #define CTLBITS(a, b, c, d)	(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
 
 #define UAA_CFG_PWRSTATUS	0x44
@@ -2173,6 +2188,9 @@
 	.is_adc_source_selected = hw_is_adc_input_selected,
 	.select_adc_source = hw_adc_input_select,
 	.have_digit_io_switch = hw_have_digit_io_switch,
+	.have_dedicated_mic = hw_have_dedicated_mic,
+	.have_output_switch = hw_have_output_switch,
+	.have_mic_source_switch = hw_have_mic_source_switch,
 #ifdef CONFIG_PM
 	.suspend = hw_suspend,
 	.resume = hw_resume,
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/cthw20k2.c
--- a/alsa-kernel/pci/ctxfi/cthw20k2.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/cthw20k2.c	Mon May 30 20:29:07 2011 +0800
@@ -8,7 +8,7 @@
  * @File	cthw20k2.c
  *
  * @Brief
- * This file contains the implementation of hardware access methord for 20k2.
+ * This file contains the implementation of hardware access method for 20k2.
  *
  * @Author	Liu Chun
  * @Date 	May 14 2008
@@ -38,6 +38,8 @@
 	unsigned char dev_id;
 	unsigned char addr_size;
 	unsigned char data_size;
+
+        int mic_source;
 };
 
 static u32 hw_read_20kx(struct hw *hw, u32 reg);
@@ -1163,17 +1165,28 @@
 		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101);
 		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
 	} else if (2 == info->msr) {
-		hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
-		/* Specify all playing 96khz
-		 * EA [0]	- Enabled
-		 * RTA [4:5]	- 96kHz
-		 * EB [8]	- Enabled
-		 * RTB [12:13]	- 96kHz
-		 * EC [16]	- Enabled
-		 * RTC [20:21]	- 96kHz
-		 * ED [24]	- Enabled
-		 * RTD [28:29]	- 96kHz */
-		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
+	        if(hw->model != CTSB1270){
+			hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111);
+			/* Specify all playing 96khz
+		 	 * EA [0]	- Enabled
+			 * RTA [4:5]	- 96kHz
+		 	 * EB [8]	- Enabled
+		 	 * RTB [12:13]	- 96kHz
+		 	 * EC [16]	- Enabled
+		 	 * RTC [20:21]	- 96kHz
+		 	 * ED [24]	- Enabled
+		 	 * RTD [28:29]	- 96kHz */
+			hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
+			hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
+		} else {
+                        /* PCM4220 on Titanium HD is different HEB FIXME */
+			hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11011111);
+			hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111);
+			hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
+		}
+	} else if ((4 == info->msr) && (hw->model == CTSB1270)) {
+		hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21011111);
+		hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
 		hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
 	} else {
 		printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n");
@@ -1182,6 +1195,8 @@
 
 	for (i = 0; i < 8; i++) {
 		if (i <= 3) {
+			/* This comment looks wrong since loop is over 4  */
+			/* channels and emu20k2 supports 4 spdif IOs. HEB */
 			/* 1st 3 channels are SPDIFs (SB0960) */
 			if (i == 3)
 				data = 0x1001001;
@@ -1206,12 +1221,16 @@
 
 			hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B);
 		} else {
+			/* Again, loop is over 4 channels not 5. HEB */
 			/* Next 5 channels are I2S (SB0960) */
 			data = 0x11;
 			hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data);
 			if (2 == info->msr) {
 				/* Four channels per sample period */
 				data |= 0x1000;
+			} else if (4 == info->msr) {
+	                        /* FIXME: check this against the chip spec */
+				data |= 0x2000;
 			}
 			hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data);
 		}
@@ -1292,57 +1311,65 @@
 
 static int hw_pll_init(struct hw *hw, unsigned int rsr)
 {
+	/* The previous verion of this wasn't reliably initializing the */
+	/* PLL when the rsr was 44100.  It was overshooting to 48000.   */
+	/* I have increased the delay from 40ms to 100ms, changed the   */
+	/* initial frequency setting for 44100 to be a bit lower to try */
+	/* to avoid overshoot and put in a loop to retry the whole      */
+	/* procedure if it fails.                                       */
+
 	unsigned int pllenb;
 	unsigned int pllctl;
 	unsigned int pllstat;
-	int i;
-
-	pllenb = 0xB;
-	hw_write_20kx(hw, PLL_ENB, pllenb);
-	pllctl = 0x20D00000;
-	set_field(&pllctl, PLLCTL_FD, 16 - 4);
-	hw_write_20kx(hw, PLL_CTL, pllctl);
-	mdelay(40);
-	pllctl = hw_read_20kx(hw, PLL_CTL);
-	set_field(&pllctl, PLLCTL_B, 0);
-	if (48000 == rsr) {
-		set_field(&pllctl, PLLCTL_FD, 16 - 2);
-		set_field(&pllctl, PLLCTL_RD, 1 - 1);
-	} else { /* 44100 */
-		set_field(&pllctl, PLLCTL_FD, 147 - 2);
-		set_field(&pllctl, PLLCTL_RD, 10 - 1);
+	int i, ok;
+	for( i = 0, ok = 0; (i < 5) && !ok; i++ ){
+                /* Try disabling the pll first to see if that helps. */
+                pllenb = hw_read_20kx(hw, PLL_ENB);
+		hw_write_20kx(hw, PLL_ENB, (pllenb & (~0x07)));
+
+		pllctl = 0x20D00000;
+		if (48000 == rsr)
+		  set_field(&pllctl, PLLCTL_FD, 16 - 4);
+		else
+		  set_field(&pllctl, PLLCTL_FD, 15 - 4);
+		hw_write_20kx(hw, PLL_CTL, pllctl);
+
+                pllenb = 0xB;
+		hw_write_20kx(hw, PLL_ENB, pllenb);
+
+		mdelay(100);
+
+		pllctl = hw_read_20kx(hw, PLL_CTL);
+		set_field(&pllctl, PLLCTL_B, 0);
+		if (48000 == rsr) {
+		  set_field(&pllctl, PLLCTL_FD, 16 - 2);
+		  set_field(&pllctl, PLLCTL_RD, 1 - 1);
+		} else { /* 44100 */
+		  set_field(&pllctl, PLLCTL_FD, 147 - 2);
+		  set_field(&pllctl, PLLCTL_RD, 10 - 1);
+		}
+		hw_write_20kx(hw, PLL_CTL, pllctl);
+
+		mdelay(100);
+
+		pllstat = hw_read_20kx(hw, PLL_STAT);
+
+		ok = (!get_field(pllstat, PLLSTAT_PD)	&&
+ 	            (get_field(pllstat, PLLSTAT_B)   ==
+		     get_field(pllctl, PLLCTL_B))       &&
+		    (get_field(pllstat, PLLSTAT_CCS) ==
+		     get_field(pllctl, PLLCTL_SRC))     &&
+		    (get_field(pllstat, PLLSTAT_CRD) ==
+		     get_field(pllctl, PLLCTL_RD))      &&
+	            (get_field(pllstat, PLLSTAT_CFD) ==
+		     get_field(pllctl, PLLCTL_FD)));
 	}
-	hw_write_20kx(hw, PLL_CTL, pllctl);
-	mdelay(40);
-	for (i = 0; i < 1000; i++) {
-		pllstat = hw_read_20kx(hw, PLL_STAT);
-		if (get_field(pllstat, PLLSTAT_PD))
-			continue;
-
-		if (get_field(pllstat, PLLSTAT_B) !=
-					get_field(pllctl, PLLCTL_B))
-			continue;
-
-		if (get_field(pllstat, PLLSTAT_CCS) !=
-					get_field(pllctl, PLLCTL_SRC))
-			continue;
-
-		if (get_field(pllstat, PLLSTAT_CRD) !=
-					get_field(pllctl, PLLCTL_RD))
-			continue;
-
-		if (get_field(pllstat, PLLSTAT_CFD) !=
-					get_field(pllctl, PLLCTL_FD))
-			continue;
-
-		break;
-	}
-	if (i >= 1000) {
-		printk(KERN_ALERT "ctxfi: PLL initialization failed!!!\n");
-		return -EBUSY;
-	}
-
-	return 0;
+
+	if( !ok || ( i > 1 ))
+	        printk(KERN_ALERT "ctxfi: PLL init rsr:%d %d/%d OK.\n",
+				  rsr, ok, i );
+
+	return ok ? 0 : -EBUSY;
 }
 
 static int hw_auto_init(struct hw *hw)
@@ -1557,7 +1584,7 @@
 
 	hw_write_20kx(hw, I2C_IF_STATUS, i2c_status);
 	hw20k2_i2c_wait_data_ready(hw);
-	/* Dummy write to trigger the write oprtation */
+	/* Dummy write to trigger the write operation */
 	hw_write_20kx(hw, I2C_IF_WDATA, 0);
 	hw20k2_i2c_wait_data_ready(hw);
 
@@ -1568,6 +1595,32 @@
 	return 0;
 }
 
+static void hw_dac_stop(struct hw *hw)
+{
+        u32 data;
+
+        data = hw_read_20kx(hw, GPIO_DATA);
+	data &= 0xFFFFFFFD;
+	hw_write_20kx(hw, GPIO_DATA, data);
+	mdelay(10);
+}
+
+static void hw_dac_start(struct hw *hw)
+{
+        u32 data;
+
+        data = hw_read_20kx(hw, GPIO_DATA);
+	data |= 0x2;
+	hw_write_20kx(hw, GPIO_DATA, data);
+	mdelay(50);
+}
+
+static void hw_dac_reset(struct hw *hw)
+{
+        hw_dac_stop(hw);
+        hw_dac_start(hw);
+}
+
 static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
 {
 	int err;
@@ -1594,6 +1647,21 @@
 				   0x00000000   /* Vol Control B4 */
 				 };
 
+	if(hw->model == CTSB1270){
+                hw_dac_stop(hw);
+		data = hw_read_20kx(hw, GPIO_DATA);
+		data &= ~0x0600;
+		if (1 == info->msr)
+			data |= 0x0000; /* Single Speed Mode 0-50kHz */
+		else if (2 == info->msr)
+			data |= 0x0200; /* Double Speed Mode 50-100kHz */
+		else
+			data |= 0x0600; /* Quad Speed Mode 100-200kHz */
+		hw_write_20kx(hw, GPIO_DATA, data);
+                hw_dac_start(hw);
+		return 0;
+	}
+
 	/* Set DAC reset bit as output */
 	data = hw_read_20kx(hw, GPIO_CTRL);
 	data |= 0x02;
@@ -1606,23 +1674,8 @@
 	for (i = 0; i < 2; i++) {
 		/* Reset DAC twice just in-case the chip
 		 * didn't initialized properly */
-		data = hw_read_20kx(hw, GPIO_DATA);
-		/* GPIO data bit 1 */
-		data &= 0xFFFFFFFD;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(10);
-		data |= 0x2;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(50);
-
-		/* Reset the 2nd time */
-		data &= 0xFFFFFFFD;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(10);
-		data |= 0x2;
-		hw_write_20kx(hw, GPIO_DATA, data);
-		mdelay(50);
-
+                hw_dac_reset(hw);
+	        hw_dac_reset(hw);
 		if (hw20k2_i2c_read(hw, CS4382_MC1,  &cs_read.mode_control_1))
 			continue;
 
@@ -1725,7 +1778,11 @@
 static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
 {
 	u32 data;
-
+	if(hw->model == CTSB1270){
+	  /* Titanium HD has two ADC chips, one for line in and one for MIC.*/
+	  /* We don't need to switch the ADC input. */
+	  return 1;
+	}
 	data = hw_read_20kx(hw, GPIO_DATA);
 	switch (type) {
 	case ADC_MICIN:
@@ -1740,31 +1797,33 @@
 	return data;
 }
 
+static void hw_wm8775_input_select(struct hw *hw, u32 input, u32 gain)
+{
+        u32 adcmc = ((u32)1 << input) | 0x100; /* Link L+R gain... */
+
+        hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, adcmc),
+				MAKE_WM8775_DATA(adcmc));
+        hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, gain),
+				MAKE_WM8775_DATA(gain));
+        /* ...so there should be no need for the following. */
+        hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, gain),
+				MAKE_WM8775_DATA(gain));
+}
+
 static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
 {
 	u32 data;
-
 	data = hw_read_20kx(hw, GPIO_DATA);
 	switch (type) {
 	case ADC_MICIN:
 		data |= (0x1 << 14);
 		hw_write_20kx(hw, GPIO_DATA, data);
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
-				MAKE_WM8775_DATA(0x101)); /* Mic-in */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7),
-				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7),
-				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
+                hw_wm8775_input_select(hw,0,0xE7); /* Mic, 12dB */
 		break;
 	case ADC_LINEIN:
 		data &= ~(0x1 << 14);
 		hw_write_20kx(hw, GPIO_DATA, data);
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
-				MAKE_WM8775_DATA(0x102)); /* Line-in */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
+                hw_wm8775_input_select(hw,1,0xCF); /* Line-in, 0dB */
 		break;
 	default:
 		break;
@@ -1776,7 +1835,7 @@
 static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
 {
 	int err;
-	u32 mux = 2, data, ctl;
+	u32 data, ctl;
 
 	/*  Set ADC reset bit as output */
 	data = hw_read_20kx(hw, GPIO_CTRL);
@@ -1793,16 +1852,37 @@
 	/* Make ADC in normal operation */
 	data = hw_read_20kx(hw, GPIO_DATA);
 	data &= ~(0x1 << 15);
+	/* FIXME? This didn't actually do a reset! */
+	hw_write_20kx(hw, GPIO_DATA, data);
+
+	if(hw->model == CTSB1270){
+		/* Set up the PCM4220 ADC on Titanium HD */
+		data &= ~0x0C;
+		if (1 == info->msr)
+			data |= 0x00; /* Single Speed Mode 32-50kHz */
+		else if (2 == info->msr)
+			data |= 0x08; /* Double Speed Mode 50-108kHz */
+		else
+		 	data |= 0x04; /* Quad Speed Mode 108kHz-216kHz */
+		hw_write_20kx(hw, GPIO_DATA, data);
+	}
+
 	mdelay(10);
 	data |= (0x1 << 15);
 	hw_write_20kx(hw, GPIO_DATA, data);
 	mdelay(50);
 
+	/* HEB FIXME - break previous cards and not required anyway? */
+        hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_IC, 0x26),
+			 MAKE_WM8775_DATA(0x26));
+
 	/* Set the master mode (256fs) */
 	if (1 == info->msr) {
+		/* slave mode, 128x oversampling 256fs */
 		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02),
 						MAKE_WM8775_DATA(0x02));
-	} else if (2 == info->msr) {
+	} else if ((2 == info->msr) || (4 == info->msr)){
+		/* slave mode, 64x oversampling, 256fs */
 		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A),
 						MAKE_WM8775_DATA(0x0A));
 	} else {
@@ -1812,45 +1892,18 @@
 		goto error;
 	}
 
-	/* Configure GPIO bit 14 change to line-in/mic-in */
-	ctl = hw_read_20kx(hw, GPIO_CTRL);
-	ctl |= 0x1 << 14;
-	hw_write_20kx(hw, GPIO_CTRL, ctl);
-
-	/* Check using Mic-in or Line-in */
-	data = hw_read_20kx(hw, GPIO_DATA);
-
-	if (mux == 1) {
-		/* Configures GPIO data to select Mic-in */
-		data |= 0x1 << 14;
-		hw_write_20kx(hw, GPIO_DATA, data);
-
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
-				MAKE_WM8775_DATA(0x101)); /* Mic-in */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7),
-				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7),
-				MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
-	} else if (mux == 2) {
-		/* Configures GPIO data to select Line-in */
-		data &= ~(0x1 << 14);
-		hw_write_20kx(hw, GPIO_DATA, data);
-
-		/* Setup ADC */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102),
-				MAKE_WM8775_DATA(0x102)); /* Line-in */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
-		hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF),
-				MAKE_WM8775_DATA(0xCF)); /* No boost */
+	if(hw->model != CTSB1270){
+		/* Configure GPIO bit 14 change to line-in/mic-in */
+		ctl = hw_read_20kx(hw, GPIO_CTRL);
+		ctl |= 0x1 << 14;
+		hw_write_20kx(hw, GPIO_CTRL, ctl);
+
+		hw_adc_input_select(hw, ADC_LINEIN);
 	} else {
-		printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n");
-		err = -EINVAL;
-		goto error;
+                hw_wm8775_input_select(hw, 0, 0xCF);
 	}
 
 	return 0;
-
 error:
 	hw20k2_i2c_uninit(hw);
 	return err;
@@ -1861,6 +1914,102 @@
 	return 0;
 }
 
+static int hw_have_dedicated_mic(struct hw *hw)
+{
+	return hw->model == CTSB1270;
+}
+
+static int hw_have_output_switch(struct hw *hw)
+{
+	return hw->model == CTSB1270;
+}
+
+static int hw_output_switch_get(struct hw *hw)
+{
+	u32 data = hw_read_20kx(hw, GPIO_EXT_DATA);
+
+	switch(data&0x30){
+	case 0x00:
+	     return 0;
+	case 0x10:
+	     return 1;
+	case 0x20:
+	     return 2;
+	default:
+	     return 3;
+	}
+}
+
+static int hw_output_switch_put(struct hw *hw,int position)
+{
+        u32 data;
+
+        if( position == hw_output_switch_get(hw) )
+	    return 0;
+
+	/* Mute line and headphones (intended for anti-pop). */
+        data = hw_read_20kx(hw, GPIO_DATA);
+	data |= (0x03 << 11);
+	hw_write_20kx(hw, GPIO_DATA, data);
+
+	data = hw_read_20kx(hw, GPIO_EXT_DATA) & ~0x30;
+	switch(position){
+	case 0:
+	        break;
+	case 1:
+	        data |= 0x10;
+	        break;
+	default:
+	        data |= 0x20;
+	}
+	hw_write_20kx(hw, GPIO_EXT_DATA, data);
+
+	/* Unmute line and headphones. */
+        data = hw_read_20kx(hw, GPIO_DATA);
+	data &= ~(0x03 << 11);
+	hw_write_20kx(hw, GPIO_DATA, data);
+
+	return 1;
+}
+
+static int hw_have_mic_source_switch(struct hw *hw)
+{
+	return hw->model == CTSB1270;
+}
+
+static int hw_mic_source_switch_get(struct hw *hw)
+{
+	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+
+        return hw20k2->mic_source;
+}
+
+static int hw_mic_source_switch_put(struct hw *hw,int position)
+{
+	struct hw20k2 *hw20k2 = (struct hw20k2 *)hw;
+
+        if( position == hw20k2->mic_source )
+	    return 0;
+
+	switch (position) {
+	case 0:
+                hw_wm8775_input_select(hw, 0, 0xCF); /* Mic, 0dB */
+		break;
+	case 1:
+	        hw_wm8775_input_select(hw, 1, 0xCF); /* FP Mic, 0dB */
+		break;
+	case 2:
+	        hw_wm8775_input_select(hw, 3, 0xCF); /* Aux Ext, 0dB */
+		break;
+	default:
+                return 0;
+	}
+
+        hw20k2->mic_source = position;
+
+	return 1;
+}
+
 static irqreturn_t ct_20k2_interrupt(int irq, void *dev_id)
 {
 	struct hw *hw = dev_id;
@@ -2015,13 +2164,16 @@
 	/* Reset all SRC pending interrupts */
 	hw_write_20kx(hw, SRC_IP, 0);
 
-	/* TODO: detect the card ID and configure GPIO accordingly. */
-	/* Configures GPIO (0xD802 0x98028) */
-	/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
-	/* Configures GPIO (SB0880) */
-	/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
-	hw_write_20kx(hw, GPIO_CTRL, 0xD802);
-
+	if(hw->model != CTSB1270){
+		/* TODO: detect the card ID and configure GPIO accordingly. */
+		/* Configures GPIO (0xD802 0x98028) */
+		/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
+		/* Configures GPIO (SB0880) */
+		/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
+		hw_write_20kx(hw, GPIO_CTRL, 0xD802);
+	} else {
+		hw_write_20kx(hw, GPIO_CTRL, 0x9E5F);
+	}
 	/* Enable audio ring */
 	hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01);
 
@@ -2099,6 +2251,13 @@
 	.is_adc_source_selected = hw_is_adc_input_selected,
 	.select_adc_source = hw_adc_input_select,
 	.have_digit_io_switch = hw_have_digit_io_switch,
+	.have_dedicated_mic = hw_have_dedicated_mic,
+	.have_output_switch = hw_have_output_switch,
+	.output_switch_get = hw_output_switch_get,
+	.output_switch_put = hw_output_switch_put,
+	.have_mic_source_switch = hw_have_mic_source_switch,
+	.mic_source_switch_get = hw_mic_source_switch_get,
+	.mic_source_switch_put = hw_mic_source_switch_put,
 #ifdef CONFIG_PM
 	.suspend = hw_suspend,
 	.resume = hw_resume,
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/ctmixer.c
--- a/alsa-kernel/pci/ctxfi/ctmixer.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/ctmixer.c	Mon May 30 20:29:07 2011 +0800
@@ -179,7 +179,6 @@
 		.ctl = 1,
 		.name = "Surround Playback Volume",
 	},
-
 	[MIXER_PCM_C_S] = {
 		.ctl = 1,
 		.name = "PCM Capture Switch",
@@ -236,6 +235,8 @@
 static void
 ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
 
+/* FIXME: this static looks like it would fail if more than one card was */
+/* installed. */
 static struct snd_kcontrol *kctls[2] = {NULL};
 
 static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index)
@@ -420,6 +421,76 @@
 	.tlv		= { .p =  ct_vol_db_scale },
 };
 
+static int output_switch_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *info)
+{
+	static const char *const names[3] = {
+	  "FP Headphones", "Headphones", "Speakers"
+	};
+
+	return snd_ctl_enum_info(info, 1, 3, names);
+}
+
+static int output_switch_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.enumerated.item[0] = atc->output_switch_get(atc);
+	return 0;
+}
+
+static int output_switch_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+	if (ucontrol->value.enumerated.item[0] > 2)
+		return -EINVAL;
+	return atc->output_switch_put(atc,ucontrol->value.enumerated.item[0]);
+}
+
+static struct snd_kcontrol_new output_ctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Analog Output Playback Enum",
+	.info = output_switch_info,
+	.get = output_switch_get,
+	.put = output_switch_put,
+};
+
+static int mic_source_switch_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *info)
+{
+	static const char *const names[3] = {
+	  "Mic", "Front Mic", "Aux"
+	};
+
+	return snd_ctl_enum_info(info, 1, 3, names);
+}
+
+static int mic_source_switch_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.enumerated.item[0] = atc->mic_source_switch_get(atc);
+	return 0;
+}
+
+static int mic_source_switch_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
+	if (ucontrol->value.enumerated.item[0] > 2)
+		return -EINVAL;
+	return atc->mic_source_switch_put(atc,ucontrol->value.enumerated.item[0]);
+}
+
+static struct snd_kcontrol_new mic_source_ctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Mic Source Capture Enum",
+	.info = mic_source_switch_info,
+	.get = mic_source_switch_get,
+	.put = mic_source_switch_put,
+};
+
 static void
 do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type)
 {
@@ -477,8 +548,15 @@
 		}
 	}
 	/* Do changes out of mixer. */
-	if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
-		do_line_mic_switch(atc, type);
+	if (!atc->have_dedicated_mic(atc) &&
+		state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type))
+	    do_line_mic_switch(atc, type);
+	else if (atc->have_dedicated_mic(atc) && (MIXER_LINEIN_C_S == type))
+	     	atc->line_in_unmute(atc, state);
+	else if (atc->have_dedicated_mic(atc) && (MIXER_MIC_C_S == type))
+	     	atc->mic_unmute(atc, state);
+	else if (atc->have_dedicated_mic(atc) && (MIXER_SPDIFI_C_S == type))
+	     	atc->spdif_in_unmute(atc, state);
 	else if (MIXER_WAVEF_P_S == type)
 		atc->line_front_unmute(atc, state);
 	else if (MIXER_WAVES_P_S == type)
@@ -695,6 +773,11 @@
 
 	ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl =
 					atc->have_digit_io_switch(atc);
+	ct_kcontrol_init_table[MIXER_LINEIN_P_S].ctl =
+					!atc->have_dedicated_mic(atc);
+	ct_kcontrol_init_table[MIXER_SPDIFI_P_S].ctl =
+					!atc->have_dedicated_mic(atc);
+
 	for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) {
 		if (ct_kcontrol_init_table[type].ctl) {
 			swh_ctl.name = ct_kcontrol_init_table[type].name;
@@ -717,6 +800,14 @@
 	if (err)
 		return err;
 
+	if(atc->have_output_switch(atc))
+		if( (err = ct_mixer_kcontrol_new(mixer, &output_ctl)) )
+			return err;
+
+	if(atc->have_mic_source_switch(atc))
+		if( (err = ct_mixer_kcontrol_new(mixer, &mic_source_ctl)) )
+			return err;
+
 	atc->line_front_unmute(atc, 1);
 	set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
 	atc->line_surround_unmute(atc, 0);
@@ -728,10 +819,13 @@
 	atc->spdif_out_unmute(atc, 0);
 	set_switch_state(mixer, MIXER_SPDIFO_P_S, 0);
 	atc->line_in_unmute(atc, 0);
-	set_switch_state(mixer, MIXER_LINEIN_P_S, 0);
+	if(!atc->have_dedicated_mic(atc))
+		set_switch_state(mixer, MIXER_LINEIN_P_S, 0);
+	if(atc->have_dedicated_mic(atc))
+		atc->mic_unmute(atc, 0);
 	atc->spdif_in_unmute(atc, 0);
-	set_switch_state(mixer, MIXER_SPDIFI_P_S, 0);
-
+	if(!atc->have_dedicated_mic(atc))
+		set_switch_state(mixer, MIXER_SPDIFI_P_S, 0);
 	set_switch_state(mixer, MIXER_PCM_C_S, 1);
 	set_switch_state(mixer, MIXER_LINEIN_C_S, 1);
 	set_switch_state(mixer, MIXER_SPDIFI_C_S, 1);
diff -r 1cc948641567 -r cb1f8f63d000 alsa-kernel/pci/ctxfi/xfi.c
--- a/alsa-kernel/pci/ctxfi/xfi.c	Sun Apr 24 12:13:08 2011 +0800
+++ b/alsa-kernel/pci/ctxfi/xfi.c	Mon May 30 20:29:07 2011 +0800
@@ -80,11 +80,11 @@
 		       "are 48000 and 44100, Value 48000 is assumed.\n");
 		reference_rate = 48000;
 	}
-	if ((multiple != 1) && (multiple != 2)) {
+	if ((multiple != 1) && (multiple != 2) && (multiple != 4)) {
 		printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n",
 		       multiple);
 		printk(KERN_ERR "ctxfi: The valid values for multiple are "
-		       "1 and 2, Value 2 is assumed.\n");
+		       "1, 2 and 4, Value 2 is assumed.\n");
 		multiple = 2;
 	}
 	err = ct_atc_create(card, pci, reference_rate, multiple,
diff -r 1cc948641567 -r cb1f8f63d000 include/pci_ids_compat.h.in
--- a/include/pci_ids_compat.h.in	Sun Apr 24 12:13:08 2011 +0800
+++ b/include/pci_ids_compat.h.in	Mon May 30 20:29:07 2011 +0800
@@ -314,6 +314,10 @@
 #define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX	0x6000
 #endif
 
+#ifndef PCI_SUBDEVICE_ID_CREATIVE_SB1270
+#define PCI_SUBDEVICE_ID_CREATIVE_SB1270 0x0062
+#endif
+
 /* ice1712 */
 #ifndef PCI_VENDOR_ID_ICE
 #define PCI_VENDOR_ID_ICE		0x1412

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 11+ messages in thread
[parent not found: <BANLkTikkMNPZ02ZmPtrJSmSEWi8nkfXsag@mail.gmail.com>]

end of thread, other threads:[~2011-06-16  5:30 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-30 13:22 Creative X-Fi Titanium HD ctxfi bugs 5378 5218 4868 Harry Butterworth
2011-06-03 15:44 ` Takashi Iwai
2011-06-11 10:35   ` Harry Butterworth
2011-06-11 10:39     ` Harry Butterworth
     [not found]   ` <BANLkTinovea9fE1Hxey83W+WAiYGBv600Q@mail.gmail.com>
2011-06-12 16:48     ` Takashi Iwai
2011-06-14  5:38       ` Takashi Iwai
2011-06-14  8:23         ` Harry Butterworth
2011-06-16  0:32           ` Harry Butterworth
2011-06-16  5:30             ` Takashi Iwai
2011-06-05  4:35 ` Marshall DeBerry
     [not found] <BANLkTikkMNPZ02ZmPtrJSmSEWi8nkfXsag@mail.gmail.com>
2011-06-03 12:26 ` Harry Butterworth

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox