Skip to content

Commit

Permalink
snd-fm801: autodetect SF64-PCR (tuner-only) card
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
  • Loading branch information
Ondrej Zary authored and tiwai committed Dec 3, 2009
1 parent 1233faa commit fb716c0
Showing 1 changed file with 27 additions and 13 deletions.
40 changes: 27 additions & 13 deletions sound/pci/fm801.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card *
* 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
* 16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card
* High 16-bits are video (radio) device number + 1
*/
static int tea575x_tuner[SNDRV_CARDS];
Expand All @@ -67,7 +67,10 @@ 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, "Enable TEA575x tuner.");
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)

/*
* Direct registers
Expand Down Expand Up @@ -160,7 +163,7 @@ 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 access method & flags */

unsigned short ply_ctrl; /* playback control */
unsigned short cap_ctrl; /* capture control */
Expand Down Expand Up @@ -1287,7 +1290,7 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
{
unsigned short cmdw;

if (chip->tea575x_tuner & 0x0010)
if (chip->tea575x_tuner & TUNER_ONLY)
goto __ac97_ok;

/* codec cold reset + AC'97 warm reset */
Expand All @@ -1296,11 +1299,13 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume)
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_INFO "Primary AC'97 codec not found, "
"assume SF64-PCR (tuner-only)\n");
chip->tea575x_tuner = 3 | TUNER_ONLY;
goto __ac97_ok;
}

if (chip->multichannel) {
if (chip->secondary_addr) {
Expand Down Expand Up @@ -1414,7 +1419,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
return err;
}
chip->port = pci_resource_start(pci, 0);
if ((tea575x_tuner & 0x0010) == 0) {
if ((tea575x_tuner & TUNER_ONLY) == 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);
Expand All @@ -1429,6 +1434,14 @@ static int __devinit snd_fm801_create(struct snd_card *card,
chip->multichannel = 1;

snd_fm801_chip_init(chip, 0);
/* init might set tuner access method */
tea575x_tuner = chip->tea575x_tuner;

if (chip->irq >= 0 && (tea575x_tuner & 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);
Expand All @@ -1438,12 +1451,13 @@ static int __devinit snd_fm801_create(struct snd_card *card,
snd_card_set_dev(card, &pci->dev);

#ifdef TEA575X_RADIO
if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) {
if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 &&
(tea575x_tuner & TUNER_TYPE_MASK) < 4) {
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 & 0x000f) - 1];
chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & TUNER_TYPE_MASK) - 1];
snd_tea575x_init(&chip->tea);
}
#endif
Expand Down Expand Up @@ -1483,7 +1497,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci,
sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, chip->port, chip->irq);

if (tea575x_tuner[dev] & 0x0010)
if (chip->tea575x_tuner & TUNER_ONLY)
goto __fm801_tuner_only;

if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) {
Expand Down

0 comments on commit fb716c0

Please sign in to comment.