lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20110610075640.GA4832@tiehlicka.suse.cz>
Date:	Fri, 10 Jun 2011 09:56:40 +0200
From:	Michal Hocko <mhocko@...e.cz>
To:	Takashi Iwai <tiwai@...e.de>
Cc:	LKML <linux-kernel@...r.kernel.org>, alsa-devel@...a-project.org
Subject: Re: [alsa-devel] Headphone output doesn't work with 3.0.0-rc* anymore

On Fri 10-06-11 08:53:01, Takashi Iwai wrote:
> At Thu, 9 Jun 2011 13:14:01 +0200,
> Michal Hocko wrote:
> > 
> > On Thu 09-06-11 11:44:41, Takashi Iwai wrote:
> > > At Thu, 9 Jun 2011 11:28:26 +0200,
[...]
> > > BTW, does my patch fix the problem when you load without model=auto?
> > 
> > I have just booted to the rc2 with the patch (https://lkml.org/lkml/2011/6/9/25)
> > and it looks it didn't solve the problem. Playback works only from
> > speakers when headphones are not plugged in - no sound if plugged in.
> 
> So, the auto-mute now works but now the headphone doesn't work.
> Weird...  Maybe the same reason the speaker doesn't work with
> auto-mode.  I saw that the only one converter keeps the stream in your
> alsa-info.sh output although multiple converters (0x02, 0x03, 0x06)
> should be used simultaneously.
> 
> > See alsa-info.txt-fresh-boot. Same thing happens if I 
> > modprobe -r snd-hda-intel and then load it again (without any parameters).
> > 
> > > If yes, does the problem appear with it?  I.e. is the silence problem
> > > specific to model=auto or not?
> > 
> > If I try to modproble with model=auto I get headphones working but not
> > output from speakers. Have a look at alsa-info.txt-modprobe_auto.
> 
> For testing, just copy 2.6.39/sound/pci/*.[ch] into 3.0 tree and
> rebuild.  

OK, I git checkout v2.6.39 -- sound/pci/*.[ch] (see the patch bellow for
reference). I have kept the earlier patch.

> Does it work as expected?  

No. There is no sound at all with or without headphones plugged in. See
attached alsa-info output (alsa-info.txt-fresh_boot_*) while mplayer was
running.
After I unloaded the module and loaded it back with model=auto
headphones started working while speakers are still silent as grave (see
alsa-info.txt-modprobe_auto_* taken while playing music).

> If you have a good-working reference, please take alsa-info.sh output
> while playing back a stream.
> 
> Note that the one-minute thing happens only when you unplug AC cable,
> supposedly.  

Hmmm, I was plugged during testing all the time. OK, this looks like a
separate issue. I will repost it as a separate thread once we are done
with this. Any idea who to CC?

> Or, simply write some value (in seconds) to
> /sys/modules/snd_hda_intel/parameters/powersave and access the device
> once (either mixer or PCM) to activate the power-saving mode.

---
>From 60d192d6cda43c358765c801dbabb94f3741a50b Mon Sep 17 00:00:00 2001
From: Michal Hocko <mhocko@...e.cz>
Date: Fri, 10 Jun 2011 09:14:27 +0200
Subject: [PATCH] Revert sound/pci/*.[ch] to 2.6.39

Takashi has suggested to revert these files to 2.6.39 to test
auto mute breakage in 3.0.0-rc[12]
---
 sound/pci/es1968.c    |   78 ----------
 sound/pci/fm801.c     |  378 +++++++++++++++++++++++++++++++++++++-----------
 sound/pci/intel8x0m.c |    4 +-
 3 files changed, 293 insertions(+), 167 deletions(-)

diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index ab0a615..7c17f45 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -112,10 +112,6 @@
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 
-#ifdef CONFIG_SND_ES1968_RADIO
-#include <sound/tea575x-tuner.h>
-#endif
-
 #define CARD_NAME "ESS Maestro1/2"
 #define DRIVER_NAME "ES1968"
 
@@ -557,10 +553,6 @@ struct es1968 {
 	spinlock_t ac97_lock;
 	struct tasklet_struct hwvol_tq;
 #endif
-
-#ifdef CONFIG_SND_ES1968_RADIO
-	struct snd_tea575x tea;
-#endif
 };
 
 static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id);
@@ -2579,63 +2571,6 @@ static int __devinit snd_es1968_input_register(struct es1968 *chip)
 }
 #endif /* CONFIG_SND_ES1968_INPUT */
 
-#ifdef CONFIG_SND_ES1968_RADIO
-#define GPIO_DATA	0x60
-#define IO_MASK		4      /* mask      register offset from GPIO_DATA
-				bits 1=unmask write to given bit */
-#define IO_DIR		8      /* direction register offset from GPIO_DATA
-				bits 0/1=read/write direction */
-/* mask bits for GPIO lines */
-#define STR_DATA	0x0040 /* GPIO6 */
-#define STR_CLK		0x0080 /* GPIO7 */
-#define STR_WREN	0x0100 /* GPIO8 */
-#define STR_MOST	0x0200 /* GPIO9 */
-
-static void snd_es1968_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
-{
-	struct es1968 *chip = tea->private_data;
-	unsigned long io = chip->io_port + GPIO_DATA;
-	u16 val = 0;
-
-	val |= (pins & TEA575X_DATA) ? STR_DATA : 0;
-	val |= (pins & TEA575X_CLK)  ? STR_CLK  : 0;
-	val |= (pins & TEA575X_WREN) ? STR_WREN : 0;
-
-	outw(val, io);
-}
-
-static u8 snd_es1968_tea575x_get_pins(struct snd_tea575x *tea)
-{
-	struct es1968 *chip = tea->private_data;
-	unsigned long io = chip->io_port + GPIO_DATA;
-	u16 val = inw(io);
-
-	return  (val & STR_DATA) ? TEA575X_DATA : 0 |
-		(val & STR_MOST) ? TEA575X_MOST : 0;
-}
-
-static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool output)
-{
-	struct es1968 *chip = tea->private_data;
-	unsigned long io = chip->io_port + GPIO_DATA;
-	u16 odir = inw(io + IO_DIR);
-
-	if (output) {
-		outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
-		outw(odir | STR_DATA | STR_CLK | STR_WREN, io + IO_DIR);
-	} else {
-		outw(~(STR_CLK | STR_WREN | STR_DATA | STR_MOST), io + IO_MASK);
-		outw((odir & ~(STR_DATA | STR_MOST)) | STR_CLK | STR_WREN, io + IO_DIR);
-	}
-}
-
-static struct snd_tea575x_ops snd_es1968_tea_ops = {
-	.set_pins = snd_es1968_tea575x_set_pins,
-	.get_pins = snd_es1968_tea575x_get_pins,
-	.set_direction = snd_es1968_tea575x_set_direction,
-};
-#endif
-
 static int snd_es1968_free(struct es1968 *chip)
 {
 #ifdef CONFIG_SND_ES1968_INPUT
@@ -2650,10 +2585,6 @@ static int snd_es1968_free(struct es1968 *chip)
 		outw(0, chip->io_port + ESM_PORT_HOST_IRQ); /* disable IRQ */
 	}
 
-#ifdef CONFIG_SND_ES1968_RADIO
-	snd_tea575x_exit(&chip->tea);
-#endif
-
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
 	snd_es1968_free_gameport(chip);
@@ -2792,15 +2723,6 @@ static int __devinit snd_es1968_create(struct snd_card *card,
 
 	snd_card_set_dev(card, &pci->dev);
 
-#ifdef CONFIG_SND_ES1968_RADIO
-	chip->tea.private_data = chip;
-	chip->tea.ops = &snd_es1968_tea_ops;
-	strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card));
-	sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
-	if (!snd_tea575x_init(&chip->tea))
-		printk(KERN_INFO "es1968: detected TEA575x radio\n");
-#endif
-
 	*chip_ret = chip;
 
 	return 0;
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index a7ec703..e1baad7 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -38,6 +38,7 @@
 
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
 #include <sound/tea575x-tuner.h>
+#define TEA575X_RADIO 1
 #endif
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@...ex.cz>");
@@ -52,7 +53,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card *
 /*
  *  Enable TEA575x tuner
  *    1 = MediaForte 256-PCS
- *    2 = MediaForte 256-PCP
+ *    2 = MediaForte 256-PCPR
  *    3 = MediaForte 64-PCR
  *   16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card
  *  High 16-bits are video (radio) device number + 1
@@ -66,7 +67,7 @@ MODULE_PARM_DESC(id, "ID string for the FM801 soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable FM801 soundcard.");
 module_param_array(tea575x_tuner, int, NULL, 0444);
-MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (0 = auto, 1 = SF256-PCS, 2=SF256-PCP, 3=SF64-PCR, 8=disable, +16=tuner-only).");
+MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (1 = SF256-PCS, 2=SF256-PCPR, 3=SF64-PCR, +16=tuner-only).");
 
 #define TUNER_ONLY		(1<<4)
 #define TUNER_TYPE_MASK		(~TUNER_ONLY & 0xFFFF)
@@ -195,7 +196,7 @@ struct fm801 {
 	spinlock_t reg_lock;
 	struct snd_info_entry *proc_entry;
 
-#ifdef CONFIG_SND_FM801_TEA575X_BOOL
+#ifdef TEA575X_RADIO
 	struct snd_tea575x tea;
 #endif
 
@@ -714,89 +715,310 @@ static int __devinit snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pc
  *  TEA5757 radio
  */
 
-#ifdef CONFIG_SND_FM801_TEA575X_BOOL
+#ifdef TEA575X_RADIO
 
-/* GPIO to TEA575x maps */
-struct snd_fm801_tea575x_gpio {
-	u8 data, clk, wren, most;
-	char *name;
-};
+/* 256PCS GPIO numbers */
+#define TEA_256PCS_DATA			1
+#define TEA_256PCS_WRITE_ENABLE		2	/* inverted */
+#define TEA_256PCS_BUS_CLOCK		3
 
-static struct snd_fm801_tea575x_gpio snd_fm801_tea575x_gpios[] = {
-	{ .data = 1, .clk = 3, .wren = 2, .most = 0, .name = "SF256-PCS" },
-	{ .data = 1, .clk = 0, .wren = 2, .most = 3, .name = "SF256-PCP" },
-	{ .data = 2, .clk = 0, .wren = 1, .most = 3, .name = "SF64-PCR" },
-};
+static void snd_fm801_tea575x_256pcs_write(struct snd_tea575x *tea, unsigned int val)
+{
+	struct fm801 *chip = tea->private_data;
+	unsigned short reg;
+	int i = 25;
 
-static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
+	spin_lock_irq(&chip->reg_lock);
+	reg = inw(FM801_REG(chip, GPIO_CTRL));
+	/* use GPIO lines and set write enable bit */
+	reg |= FM801_GPIO_GS(TEA_256PCS_DATA) |
+	       FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) |
+	       FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK);
+	/* all of lines are in the write direction */
+	/* clear data and clock lines */
+	reg &= ~(FM801_GPIO_GD(TEA_256PCS_DATA) |
+	         FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) |
+	         FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) |
+	         FM801_GPIO_GP(TEA_256PCS_DATA) |
+	         FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK) |
+		 FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE));
+	outw(reg, FM801_REG(chip, GPIO_CTRL));
+	udelay(1);
+
+	while (i--) {
+		if (val & (1 << i))
+			reg |= FM801_GPIO_GP(TEA_256PCS_DATA);
+		else
+			reg &= ~FM801_GPIO_GP(TEA_256PCS_DATA);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		udelay(1);
+		reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		udelay(1);
+	}
+
+	/* and reset the write enable bit */
+	reg |= FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE) |
+	       FM801_GPIO_GP(TEA_256PCS_DATA);
+	outw(reg, FM801_REG(chip, GPIO_CTRL));
+	spin_unlock_irq(&chip->reg_lock);
+}
+
+static unsigned int snd_fm801_tea575x_256pcs_read(struct snd_tea575x *tea)
 {
 	struct fm801 *chip = tea->private_data;
-	unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
-	struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
+	unsigned short reg;
+	unsigned int val = 0;
+	int i;
+	
+	spin_lock_irq(&chip->reg_lock);
+	reg = inw(FM801_REG(chip, GPIO_CTRL));
+	/* use GPIO lines, set data direction to input */
+	reg |= FM801_GPIO_GS(TEA_256PCS_DATA) |
+	       FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) |
+	       FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK) |
+	       FM801_GPIO_GD(TEA_256PCS_DATA) |
+	       FM801_GPIO_GP(TEA_256PCS_DATA) |
+	       FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE);
+	/* all of lines are in the write direction, except data */
+	/* clear data, write enable and clock lines */
+	reg &= ~(FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) |
+	         FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) |
+	         FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK));
+
+	for (i = 0; i < 24; i++) {
+		reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		udelay(1);
+		reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		udelay(1);
+		val <<= 1;
+		if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCS_DATA))
+			val |= 1;
+	}
 
-	reg &= ~(FM801_GPIO_GP(gpio.data) |
-		 FM801_GPIO_GP(gpio.clk) |
-		 FM801_GPIO_GP(gpio.wren));
+	spin_unlock_irq(&chip->reg_lock);
+
+	return val;
+}
 
-	reg |= (pins & TEA575X_DATA) ? FM801_GPIO_GP(gpio.data) : 0;
-	reg |= (pins & TEA575X_CLK)  ? FM801_GPIO_GP(gpio.clk) : 0;
-	/* WRITE_ENABLE is inverted */
-	reg |= (pins & TEA575X_WREN) ? 0 : FM801_GPIO_GP(gpio.wren);
+/* 256PCPR GPIO numbers */
+#define TEA_256PCPR_BUS_CLOCK		0
+#define TEA_256PCPR_DATA		1
+#define TEA_256PCPR_WRITE_ENABLE	2	/* inverted */
+
+static void snd_fm801_tea575x_256pcpr_write(struct snd_tea575x *tea, unsigned int val)
+{
+	struct fm801 *chip = tea->private_data;
+	unsigned short reg;
+	int i = 25;
+
+	spin_lock_irq(&chip->reg_lock);
+	reg = inw(FM801_REG(chip, GPIO_CTRL));
+	/* use GPIO lines and set write enable bit */
+	reg |= FM801_GPIO_GS(TEA_256PCPR_DATA) |
+	       FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) |
+	       FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK);
+	/* all of lines are in the write direction */
+	/* clear data and clock lines */
+	reg &= ~(FM801_GPIO_GD(TEA_256PCPR_DATA) |
+	         FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) |
+	         FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) |
+	         FM801_GPIO_GP(TEA_256PCPR_DATA) |
+	         FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK) |
+		 FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE));
+	outw(reg, FM801_REG(chip, GPIO_CTRL));
+	udelay(1);
+
+	while (i--) {
+		if (val & (1 << i))
+			reg |= FM801_GPIO_GP(TEA_256PCPR_DATA);
+		else
+			reg &= ~FM801_GPIO_GP(TEA_256PCPR_DATA);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		udelay(1);
+		reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		udelay(1);
+	}
 
+	/* and reset the write enable bit */
+	reg |= FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE) |
+	       FM801_GPIO_GP(TEA_256PCPR_DATA);
 	outw(reg, FM801_REG(chip, GPIO_CTRL));
+	spin_unlock_irq(&chip->reg_lock);
 }
 
-static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea)
+static unsigned int snd_fm801_tea575x_256pcpr_read(struct snd_tea575x *tea)
 {
 	struct fm801 *chip = tea->private_data;
-	unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
-	struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
+	unsigned short reg;
+	unsigned int val = 0;
+	int i;
+	
+	spin_lock_irq(&chip->reg_lock);
+	reg = inw(FM801_REG(chip, GPIO_CTRL));
+	/* use GPIO lines, set data direction to input */
+	reg |= FM801_GPIO_GS(TEA_256PCPR_DATA) |
+	       FM801_GPIO_GS(TEA_256PCPR_WRITE_ENABLE) |
+	       FM801_GPIO_GS(TEA_256PCPR_BUS_CLOCK) |
+	       FM801_GPIO_GD(TEA_256PCPR_DATA) |
+	       FM801_GPIO_GP(TEA_256PCPR_DATA) |
+	       FM801_GPIO_GP(TEA_256PCPR_WRITE_ENABLE);
+	/* all of lines are in the write direction, except data */
+	/* clear data, write enable and clock lines */
+	reg &= ~(FM801_GPIO_GD(TEA_256PCPR_WRITE_ENABLE) |
+	         FM801_GPIO_GD(TEA_256PCPR_BUS_CLOCK) |
+	         FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK));
+
+	for (i = 0; i < 24; i++) {
+		reg &= ~FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		udelay(1);
+		reg |= FM801_GPIO_GP(TEA_256PCPR_BUS_CLOCK);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		udelay(1);
+		val <<= 1;
+		if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_256PCPR_DATA))
+			val |= 1;
+	}
+
+	spin_unlock_irq(&chip->reg_lock);
 
-	return  (reg & FM801_GPIO_GP(gpio.data)) ? TEA575X_DATA : 0 |
-		(reg & FM801_GPIO_GP(gpio.most)) ? TEA575X_MOST : 0;
+	return val;
 }
 
-static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output)
+/* 64PCR GPIO numbers */
+#define TEA_64PCR_BUS_CLOCK		0
+#define TEA_64PCR_WRITE_ENABLE		1	/* inverted */
+#define TEA_64PCR_DATA			2
+
+static void snd_fm801_tea575x_64pcr_write(struct snd_tea575x *tea, unsigned int val)
 {
 	struct fm801 *chip = tea->private_data;
-	unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
-	struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1];
+	unsigned short reg;
+	int i = 25;
 
+	spin_lock_irq(&chip->reg_lock);
+	reg = inw(FM801_REG(chip, GPIO_CTRL));
 	/* use GPIO lines and set write enable bit */
-	reg |= FM801_GPIO_GS(gpio.data) |
-	       FM801_GPIO_GS(gpio.wren) |
-	       FM801_GPIO_GS(gpio.clk) |
-	       FM801_GPIO_GS(gpio.most);
-	if (output) {
-		/* all of lines are in the write direction */
-		/* clear data and clock lines */
-		reg &= ~(FM801_GPIO_GD(gpio.data) |
-			 FM801_GPIO_GD(gpio.wren) |
-			 FM801_GPIO_GD(gpio.clk) |
-			 FM801_GPIO_GP(gpio.data) |
-			 FM801_GPIO_GP(gpio.clk) |
-			 FM801_GPIO_GP(gpio.wren));
-	} else {
-		/* use GPIO lines, set data direction to input */
-		reg |= FM801_GPIO_GD(gpio.data) |
-		       FM801_GPIO_GD(gpio.most) |
-		       FM801_GPIO_GP(gpio.data) |
-		       FM801_GPIO_GP(gpio.most) |
-		       FM801_GPIO_GP(gpio.wren);
-		/* all of lines are in the write direction, except data */
-		/* clear data, write enable and clock lines */
-		reg &= ~(FM801_GPIO_GD(gpio.wren) |
-			 FM801_GPIO_GD(gpio.clk) |
-			 FM801_GPIO_GP(gpio.clk));
+	reg |= FM801_GPIO_GS(TEA_64PCR_DATA) |
+	       FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) |
+	       FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK);
+	/* all of lines are in the write direction */
+	/* clear data and clock lines */
+	reg &= ~(FM801_GPIO_GD(TEA_64PCR_DATA) |
+	         FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) |
+	         FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) |
+	         FM801_GPIO_GP(TEA_64PCR_DATA) |
+	         FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK) |
+		 FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE));
+	outw(reg, FM801_REG(chip, GPIO_CTRL));
+	udelay(1);
+
+	while (i--) {
+		if (val & (1 << i))
+			reg |= FM801_GPIO_GP(TEA_64PCR_DATA);
+		else
+			reg &= ~FM801_GPIO_GP(TEA_64PCR_DATA);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		udelay(1);
+		reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		udelay(1);
+	}
+
+	/* and reset the write enable bit */
+	reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE) |
+	       FM801_GPIO_GP(TEA_64PCR_DATA);
+	outw(reg, FM801_REG(chip, GPIO_CTRL));
+	spin_unlock_irq(&chip->reg_lock);
+}
+
+static unsigned int snd_fm801_tea575x_64pcr_read(struct snd_tea575x *tea)
+{
+	struct fm801 *chip = tea->private_data;
+	unsigned short reg;
+	unsigned int val = 0;
+	int i;
+	
+	spin_lock_irq(&chip->reg_lock);
+	reg = inw(FM801_REG(chip, GPIO_CTRL));
+	/* use GPIO lines, set data direction to input */
+	reg |= FM801_GPIO_GS(TEA_64PCR_DATA) |
+	       FM801_GPIO_GS(TEA_64PCR_WRITE_ENABLE) |
+	       FM801_GPIO_GS(TEA_64PCR_BUS_CLOCK) |
+	       FM801_GPIO_GD(TEA_64PCR_DATA) |
+	       FM801_GPIO_GP(TEA_64PCR_DATA) |
+	       FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);
+	/* all of lines are in the write direction, except data */
+	/* clear data, write enable and clock lines */
+	reg &= ~(FM801_GPIO_GD(TEA_64PCR_WRITE_ENABLE) |
+	         FM801_GPIO_GD(TEA_64PCR_BUS_CLOCK) |
+	         FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK));
+
+	for (i = 0; i < 24; i++) {
+		reg &= ~FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		udelay(1);
+		reg |= FM801_GPIO_GP(TEA_64PCR_BUS_CLOCK);
+		outw(reg, FM801_REG(chip, GPIO_CTRL));
+		udelay(1);
+		val <<= 1;
+		if (inw(FM801_REG(chip, GPIO_CTRL)) & FM801_GPIO_GP(TEA_64PCR_DATA))
+			val |= 1;
 	}
 
+	spin_unlock_irq(&chip->reg_lock);
+
+	return val;
+}
+
+static void snd_fm801_tea575x_64pcr_mute(struct snd_tea575x *tea,
+					  unsigned int mute)
+{
+	struct fm801 *chip = tea->private_data;
+	unsigned short reg;
+
+	spin_lock_irq(&chip->reg_lock);
+
+	reg = inw(FM801_REG(chip, GPIO_CTRL));
+	if (mute)
+		/* 0xf800 (mute) */
+		reg &= ~FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);
+	else
+		/* 0xf802 (unmute) */
+		reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);
 	outw(reg, FM801_REG(chip, GPIO_CTRL));
+	udelay(1);
+
+	spin_unlock_irq(&chip->reg_lock);
 }
 
-static struct snd_tea575x_ops snd_fm801_tea_ops = {
-	.set_pins = snd_fm801_tea575x_set_pins,
-	.get_pins = snd_fm801_tea575x_get_pins,
-	.set_direction = snd_fm801_tea575x_set_direction,
+static struct snd_tea575x_ops snd_fm801_tea_ops[3] = {
+	{
+		/* 1 = MediaForte 256-PCS */
+		.write = snd_fm801_tea575x_256pcs_write,
+		.read = snd_fm801_tea575x_256pcs_read,
+	},
+	{
+		/* 2 = MediaForte 256-PCPR */
+		.write = snd_fm801_tea575x_256pcpr_write,
+		.read = snd_fm801_tea575x_256pcpr_read,
+	},
+	{
+		/* 3 = MediaForte 64-PCR */
+		.write = snd_fm801_tea575x_64pcr_write,
+		.read = snd_fm801_tea575x_64pcr_read,
+		.mute = snd_fm801_tea575x_64pcr_mute,
+	}
 };
 #endif
 
@@ -1149,7 +1371,7 @@ static int snd_fm801_free(struct fm801 *chip)
 	outw(cmdw, FM801_REG(chip, IRQ_MASK));
 
       __end_hw:
-#ifdef CONFIG_SND_FM801_TEA575X_BOOL
+#ifdef TEA575X_RADIO
 	snd_tea575x_exit(&chip->tea);
 #endif
 	if (chip->irq >= 0)
@@ -1228,34 +1450,16 @@ static int __devinit snd_fm801_create(struct snd_card *card,
 
 	snd_card_set_dev(card, &pci->dev);
 
-#ifdef CONFIG_SND_FM801_TEA575X_BOOL
-	chip->tea.private_data = chip;
-	chip->tea.ops = &snd_fm801_tea_ops;
-	sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
+#ifdef TEA575X_RADIO
 	if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
 	    (tea575x_tuner & TUNER_TYPE_MASK) < 4) {
-		if (snd_tea575x_init(&chip->tea)) {
-			snd_printk(KERN_ERR "TEA575x radio not found\n");
-			snd_fm801_free(chip);
-			return -ENODEV;
-		}
-	} else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) {
-		/* autodetect tuner connection */
-		for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) {
-			chip->tea575x_tuner = tea575x_tuner;
-			if (!snd_tea575x_init(&chip->tea)) {
-				snd_printk(KERN_INFO "detected TEA575x radio type %s\n",
-					snd_fm801_tea575x_gpios[tea575x_tuner - 1].name);
-				break;
-			}
-		}
-		if (tea575x_tuner == 4) {
-			snd_printk(KERN_ERR "TEA575x radio not found\n");
-			snd_fm801_free(chip);
-			return -ENODEV;
-		}
+		chip->tea.dev_nr = tea575x_tuner >> 16;
+		chip->tea.card = card;
+		chip->tea.freq_fixup = 10700;
+		chip->tea.private_data = chip;
+		chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & TUNER_TYPE_MASK) - 1];
+		snd_tea575x_init(&chip->tea);
 	}
-	strlcpy(chip->tea.card, snd_fm801_tea575x_gpios[(tea575x_tuner & TUNER_TYPE_MASK) - 1].name, sizeof(chip->tea.card));
 #endif
 
 	*rchip = chip;
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index f3353b4..27709f0 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -235,8 +235,8 @@ static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0m_ids) = {
 	{ PCI_VDEVICE(NVIDIA, 0x0069), DEVICE_NFORCE }, /* NFORCE2 */
 	{ PCI_VDEVICE(NVIDIA, 0x0089), DEVICE_NFORCE }, /* NFORCE2s */
 	{ PCI_VDEVICE(NVIDIA, 0x00d9), DEVICE_NFORCE }, /* NFORCE3 */
-	{ PCI_VDEVICE(AMD, 0x746e), DEVICE_INTEL },	/* AMD8111 */
 #if 0
+	{ PCI_VDEVICE(AMD, 0x746d), DEVICE_INTEL },	/* AMD8111 */
 	{ PCI_VDEVICE(AL, 0x5455), DEVICE_ALI },   /* Ali5455 */
 #endif
 	{ 0, }
@@ -1261,9 +1261,9 @@ static struct shortname_table {
 	{ PCI_DEVICE_ID_NVIDIA_MCP2_MODEM, "NVidia nForce2" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM, "NVidia nForce2s" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP3_MODEM, "NVidia nForce3" },
-	{ 0x746e, "AMD AMD8111" },
 #if 0
 	{ 0x5455, "ALi M5455" },
+	{ 0x746d, "AMD AMD8111" },
 #endif
 	{ 0 },
 };
-- 
1.7.5.3

-- 
Michal Hocko
SUSE Labs
SUSE LINUX s.r.o.
Lihovarska 1060/12
190 00 Praha 9    
Czech Republic
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ