[alsa-devel] snd-fm801: autodetect SF64-PCR (tuner-only) card

Ondrej Zary linux at rainbow-software.org
Thu Nov 26 21:59:43 CET 2009


When primary AC97 is not found, don't fail with tons of AC97 errors.
Assume that the card is SF64-PCR (tuner-only).
This makes the SF64-PCR radio card work "out of the box".

Also fixes a bug that can cause an oops here:
	if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) {
when tea575x_tuner == 16, it passes this check and causes problems
a couple lines below:
	chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1];


Tested with SF64-PCR, but I don't have any of those sound or sound+radio cards
to test if I didn't break anything.


Signed-off-by: Ondrej Zary <linux at rainbow-software.org>

--- linux-source-2.6.31-orig/sound/pci/fm801.c	2009-09-10 00:13:59.000000000 +0200
+++ linux-source-2.6.31/sound/pci/fm801.c	2009-11-26 21:19:59.000000000 +0100
@@ -55,7 +55,6 @@ static int enable[SNDRV_CARDS] = SNDRV_D
  *    1 = MediaForte 256-PCS
  *    2 = MediaForte 256-PCPR
  *    3 = MediaForte 64-PCR
- *   16 = setup tuner only (this is additional bit), i.e. SF-64-PCR FM card
  *  High 16-bits are video (radio) device number + 1
  */
 static int tea575x_tuner[SNDRV_CARDS];
@@ -67,7 +66,7 @@ MODULE_PARM_DESC(id, "ID string for the 
 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, "Enable TEA575x tuner.");
+MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner type (1 = SF256-PCS, 2=SF256-PCPR, 3=SF64-PCR).");
 
 /*
  *  Direct registers
@@ -160,7 +159,8 @@ struct fm801 {
 	unsigned int multichannel: 1,	/* multichannel support */
 		     secondary: 1;	/* secondary codec */
 	unsigned char secondary_addr;	/* address of the secondary codec */
-	unsigned int tea575x_tuner;	/* tuner flags */
+	unsigned int tea575x_tuner;	/* tuner type */
+	bool tuner_only;
 
 	unsigned short ply_ctrl; /* playback control */
 	unsigned short cap_ctrl; /* capture control */
@@ -1287,20 +1287,20 @@ static int snd_fm801_chip_init(struct fm
 {
 	unsigned short cmdw;
 
-	if (chip->tea575x_tuner & 0x0010)
-		goto __ac97_ok;
-
 	/* codec cold reset + AC'97 warm reset */
 	outw((1<<5) | (1<<6), FM801_REG(chip, CODEC_CTRL));
 	inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */
 	udelay(100);
 	outw(0, FM801_REG(chip, CODEC_CTRL));
 
-	if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) {
-		snd_printk(KERN_ERR "Primary AC'97 codec not found\n");
-		if (! resume)
-			return -EIO;
-	}
+	if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0)
+		if (!resume) {
+			snd_printk(KERN_ERR "Primary AC'97 codec not found, "
+					    "assume SF64-PCR (tuner-only)\n");
+			chip->tuner_only = 1;
+			chip->tea575x_tuner = 3;
+			goto __ac97_ok;
+		}
 
 	if (chip->multichannel) {
 		if (chip->secondary_addr) {
@@ -1414,21 +1414,27 @@ static int __devinit snd_fm801_create(st
 		return err;
 	}
 	chip->port = pci_resource_start(pci, 0);
-	if ((tea575x_tuner & 0x0010) == 0) {
-		if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
-				"FM801", chip)) {
-			snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
-			snd_fm801_free(chip);
-			return -EBUSY;
-		}
-		chip->irq = pci->irq;
-		pci_set_master(pci);
+	if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
+			"FM801", chip)) {
+		snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq);
+		snd_fm801_free(chip);
+		return -EBUSY;
 	}
+	chip->irq = pci->irq;
+	pci_set_master(pci);
 
 	if (pci->revision >= 0xb1)	/* FM801-AU */
 		chip->multichannel = 1;
 
 	snd_fm801_chip_init(chip, 0);
+	/* init might set tuner type */
+	tea575x_tuner = chip->tea575x_tuner;
+
+	if (chip->tuner_only) {
+		pci_clear_master(pci);
+		free_irq(chip->irq, chip);
+		chip->irq = -1;
+	}
 
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
 		snd_fm801_free(chip);
@@ -1438,7 +1444,7 @@ static int __devinit snd_fm801_create(st
 	snd_card_set_dev(card, &pci->dev);
 
 #ifdef TEA575X_RADIO
-	if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) {
+	if ((tea575x_tuner & 0x000f) > 0 && (tea575x_tuner & 0x000f) < 4) {
 		chip->tea.dev_nr = tea575x_tuner >> 16;
 		chip->tea.card = card;
 		chip->tea.freq_fixup = 10700;
@@ -1483,7 +1489,7 @@ static int __devinit snd_card_fm801_prob
 	sprintf(card->longname, "%s at 0x%lx, irq %i",
 		card->shortname, chip->port, chip->irq);
 
-	if (tea575x_tuner[dev] & 0x0010)
+	if (chip->tuner_only)
 		goto __fm801_tuner_only;
 
 	if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) {

-- 
Ondrej Zary


More information about the Alsa-devel mailing list