diff options
author | Ondrej Zary <linux@rainbow-software.org> | 2009-11-27 12:18:33 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-12-03 12:25:40 -0500 |
commit | fb716c0b7bed36064cd41d800c8f339f41adf084 (patch) | |
tree | ad315acbdd00444bfd9d44f1c4545d855ff44bb2 /sound/pci/fm801.c | |
parent | 1233faa891451dee9eaddd7f8a616ba1ddd77919 (diff) |
snd-fm801: autodetect SF64-PCR (tuner-only) card
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@rainbow-software.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/fm801.c')
-rw-r--r-- | sound/pci/fm801.c | 40 |
1 files changed, 27 insertions, 13 deletions
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 60cdb9e0b68d..83508b3964fb 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c | |||
@@ -55,7 +55,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card * | |||
55 | * 1 = MediaForte 256-PCS | 55 | * 1 = MediaForte 256-PCS |
56 | * 2 = MediaForte 256-PCPR | 56 | * 2 = MediaForte 256-PCPR |
57 | * 3 = MediaForte 64-PCR | 57 | * 3 = MediaForte 64-PCR |
58 | * 16 = setup tuner only (this is additional bit), i.e. SF-64-PCR FM card | 58 | * 16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card |
59 | * High 16-bits are video (radio) device number + 1 | 59 | * High 16-bits are video (radio) device number + 1 |
60 | */ | 60 | */ |
61 | static int tea575x_tuner[SNDRV_CARDS]; | 61 | static int tea575x_tuner[SNDRV_CARDS]; |
@@ -67,7 +67,10 @@ MODULE_PARM_DESC(id, "ID string for the FM801 soundcard."); | |||
67 | module_param_array(enable, bool, NULL, 0444); | 67 | module_param_array(enable, bool, NULL, 0444); |
68 | MODULE_PARM_DESC(enable, "Enable FM801 soundcard."); | 68 | MODULE_PARM_DESC(enable, "Enable FM801 soundcard."); |
69 | module_param_array(tea575x_tuner, int, NULL, 0444); | 69 | module_param_array(tea575x_tuner, int, NULL, 0444); |
70 | MODULE_PARM_DESC(tea575x_tuner, "Enable TEA575x tuner."); | 70 | MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (1 = SF256-PCS, 2=SF256-PCPR, 3=SF64-PCR, +16=tuner-only)."); |
71 | |||
72 | #define TUNER_ONLY (1<<4) | ||
73 | #define TUNER_TYPE_MASK (~TUNER_ONLY & 0xFFFF) | ||
71 | 74 | ||
72 | /* | 75 | /* |
73 | * Direct registers | 76 | * Direct registers |
@@ -160,7 +163,7 @@ struct fm801 { | |||
160 | unsigned int multichannel: 1, /* multichannel support */ | 163 | unsigned int multichannel: 1, /* multichannel support */ |
161 | secondary: 1; /* secondary codec */ | 164 | secondary: 1; /* secondary codec */ |
162 | unsigned char secondary_addr; /* address of the secondary codec */ | 165 | unsigned char secondary_addr; /* address of the secondary codec */ |
163 | unsigned int tea575x_tuner; /* tuner flags */ | 166 | unsigned int tea575x_tuner; /* tuner access method & flags */ |
164 | 167 | ||
165 | unsigned short ply_ctrl; /* playback control */ | 168 | unsigned short ply_ctrl; /* playback control */ |
166 | unsigned short cap_ctrl; /* capture control */ | 169 | unsigned short cap_ctrl; /* capture control */ |
@@ -1287,7 +1290,7 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) | |||
1287 | { | 1290 | { |
1288 | unsigned short cmdw; | 1291 | unsigned short cmdw; |
1289 | 1292 | ||
1290 | if (chip->tea575x_tuner & 0x0010) | 1293 | if (chip->tea575x_tuner & TUNER_ONLY) |
1291 | goto __ac97_ok; | 1294 | goto __ac97_ok; |
1292 | 1295 | ||
1293 | /* codec cold reset + AC'97 warm reset */ | 1296 | /* codec cold reset + AC'97 warm reset */ |
@@ -1296,11 +1299,13 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) | |||
1296 | udelay(100); | 1299 | udelay(100); |
1297 | outw(0, FM801_REG(chip, CODEC_CTRL)); | 1300 | outw(0, FM801_REG(chip, CODEC_CTRL)); |
1298 | 1301 | ||
1299 | if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) { | 1302 | if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) |
1300 | snd_printk(KERN_ERR "Primary AC'97 codec not found\n"); | 1303 | if (!resume) { |
1301 | if (! resume) | 1304 | snd_printk(KERN_INFO "Primary AC'97 codec not found, " |
1302 | return -EIO; | 1305 | "assume SF64-PCR (tuner-only)\n"); |
1303 | } | 1306 | chip->tea575x_tuner = 3 | TUNER_ONLY; |
1307 | goto __ac97_ok; | ||
1308 | } | ||
1304 | 1309 | ||
1305 | if (chip->multichannel) { | 1310 | if (chip->multichannel) { |
1306 | if (chip->secondary_addr) { | 1311 | if (chip->secondary_addr) { |
@@ -1414,7 +1419,7 @@ static int __devinit snd_fm801_create(struct snd_card *card, | |||
1414 | return err; | 1419 | return err; |
1415 | } | 1420 | } |
1416 | chip->port = pci_resource_start(pci, 0); | 1421 | chip->port = pci_resource_start(pci, 0); |
1417 | if ((tea575x_tuner & 0x0010) == 0) { | 1422 | if ((tea575x_tuner & TUNER_ONLY) == 0) { |
1418 | if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED, | 1423 | if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED, |
1419 | "FM801", chip)) { | 1424 | "FM801", chip)) { |
1420 | snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq); | 1425 | snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq); |
@@ -1429,6 +1434,14 @@ static int __devinit snd_fm801_create(struct snd_card *card, | |||
1429 | chip->multichannel = 1; | 1434 | chip->multichannel = 1; |
1430 | 1435 | ||
1431 | snd_fm801_chip_init(chip, 0); | 1436 | snd_fm801_chip_init(chip, 0); |
1437 | /* init might set tuner access method */ | ||
1438 | tea575x_tuner = chip->tea575x_tuner; | ||
1439 | |||
1440 | if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) { | ||
1441 | pci_clear_master(pci); | ||
1442 | free_irq(chip->irq, chip); | ||
1443 | chip->irq = -1; | ||
1444 | } | ||
1432 | 1445 | ||
1433 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { | 1446 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { |
1434 | snd_fm801_free(chip); | 1447 | snd_fm801_free(chip); |
@@ -1438,12 +1451,13 @@ static int __devinit snd_fm801_create(struct snd_card *card, | |||
1438 | snd_card_set_dev(card, &pci->dev); | 1451 | snd_card_set_dev(card, &pci->dev); |
1439 | 1452 | ||
1440 | #ifdef TEA575X_RADIO | 1453 | #ifdef TEA575X_RADIO |
1441 | if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) { | 1454 | if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 && |
1455 | (tea575x_tuner & TUNER_TYPE_MASK) < 4) { | ||
1442 | chip->tea.dev_nr = tea575x_tuner >> 16; | 1456 | chip->tea.dev_nr = tea575x_tuner >> 16; |
1443 | chip->tea.card = card; | 1457 | chip->tea.card = card; |
1444 | chip->tea.freq_fixup = 10700; | 1458 | chip->tea.freq_fixup = 10700; |
1445 | chip->tea.private_data = chip; | 1459 | chip->tea.private_data = chip; |
1446 | chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1]; | 1460 | chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & TUNER_TYPE_MASK) - 1]; |
1447 | snd_tea575x_init(&chip->tea); | 1461 | snd_tea575x_init(&chip->tea); |
1448 | } | 1462 | } |
1449 | #endif | 1463 | #endif |
@@ -1483,7 +1497,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, | |||
1483 | sprintf(card->longname, "%s at 0x%lx, irq %i", | 1497 | sprintf(card->longname, "%s at 0x%lx, irq %i", |
1484 | card->shortname, chip->port, chip->irq); | 1498 | card->shortname, chip->port, chip->irq); |
1485 | 1499 | ||
1486 | if (tea575x_tuner[dev] & 0x0010) | 1500 | if (chip->tea575x_tuner & TUNER_ONLY) |
1487 | goto __fm801_tuner_only; | 1501 | goto __fm801_tuner_only; |
1488 | 1502 | ||
1489 | if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) { | 1503 | if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) { |