X-Git-Url: http://git.samba.org/samba.git/?p=sfrench%2Fcifs-2.6.git;a=blobdiff_plain;f=sound%2Fpci%2Ffm801.c;h=b7b361ce3a93bb6270807fc75b0ea31db10aa09a;hp=0afa573dd2441556e8499e7baaeff29b64b868ad;hb=4604096768d3be37ee1a05aee424aceed3e1b56f;hpb=c0897856553d45aee1780bed455b7c2e888dd64b diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 0afa573dd244..b7b361ce3a93 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -2,6 +2,7 @@ * The driver for the ForteMedia FM801 based soundcards * Copyright (c) by Jaroslav Kysela * + * Support FM only card by Andy Shevchenko * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +37,7 @@ #include -#if (defined(CONFIG_SND_FM801_TEA575X) || defined(CONFIG_SND_FM801_TEA575X_MODULE)) && (defined(CONFIG_VIDEO_DEV) || defined(CONFIG_VIDEO_DEV_MODULE)) +#ifdef CONFIG_SND_FM801_TEA575X_BOOL #include #define TEA575X_RADIO 1 #endif @@ -54,6 +56,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 * High 16-bits are video (radio) device number + 1 */ static int tea575x_tuner[SNDRV_CARDS]; @@ -158,6 +161,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 short ply_ctrl; /* playback control */ unsigned short cap_ctrl; /* capture control */ @@ -199,7 +203,7 @@ struct fm801 { #endif }; -static struct pci_device_id snd_fm801_ids[] __devinitdata = { +static struct pci_device_id snd_fm801_ids[] = { { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */ { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */ { 0, } @@ -318,10 +322,8 @@ static unsigned int channels[] = { 2, 4, 6 }; -#define CHANNELS sizeof(channels) / sizeof(channels[0]) - static struct snd_pcm_hw_constraint_list hw_constraints_channels = { - .count = CHANNELS, + .count = ARRAY_SIZE(channels), .list = channels, .mask = 0, }; @@ -518,7 +520,7 @@ static snd_pcm_uframes_t snd_fm801_capture_pointer(struct snd_pcm_substream *sub return bytes_to_frames(substream->runtime, ptr); } -static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id) { struct fm801 *chip = dev_id; unsigned short status; @@ -559,7 +561,7 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id, struct pt_regs *re snd_pcm_period_elapsed(chip->capture_substream); } if (chip->rmidi && (status & FM801_IRQ_MPU)) - snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); + snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); if (status & FM801_IRQ_VOLUME) ;/* TODO */ @@ -1052,6 +1054,13 @@ static int snd_fm801_put_single(struct snd_kcontrol *kcontrol, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_fm801_info_double, \ .get = snd_fm801_get_double, .put = snd_fm801_put_double, \ .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24) } +#define FM801_DOUBLE_TLV(xname, reg, shift_left, shift_right, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .name = xname, .info = snd_fm801_info_double, \ + .get = snd_fm801_get_double, .put = snd_fm801_put_double, \ + .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24), \ + .tlv = { .p = (xtlv) } } static int snd_fm801_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -1148,14 +1157,19 @@ static int snd_fm801_put_mux(struct snd_kcontrol *kcontrol, return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val); } +static DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0); + #define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls) static struct snd_kcontrol_new snd_fm801_controls[] __devinitdata = { -FM801_DOUBLE("Wave Playback Volume", FM801_PCM_VOL, 0, 8, 31, 1), +FM801_DOUBLE_TLV("Wave Playback Volume", FM801_PCM_VOL, 0, 8, 31, 1, + db_scale_dsp), FM801_SINGLE("Wave Playback Switch", FM801_PCM_VOL, 15, 1, 1), -FM801_DOUBLE("I2S Playback Volume", FM801_I2S_VOL, 0, 8, 31, 1), +FM801_DOUBLE_TLV("I2S Playback Volume", FM801_I2S_VOL, 0, 8, 31, 1, + db_scale_dsp), FM801_SINGLE("I2S Playback Switch", FM801_I2S_VOL, 15, 1, 1), -FM801_DOUBLE("FM Playback Volume", FM801_FM_VOL, 0, 8, 31, 1), +FM801_DOUBLE_TLV("FM Playback Volume", FM801_FM_VOL, 0, 8, 31, 1, + db_scale_dsp), FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -1253,6 +1267,9 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) int id; 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 */ @@ -1290,6 +1307,8 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750)); } + __ac97_ok: + /* init volume */ outw(0x0808, FM801_REG(chip, PCM_VOL)); outw(0x9f1f, FM801_REG(chip, FM_VOL)); @@ -1298,9 +1317,12 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) /* I2S control - I2S mode */ outw(0x0003, FM801_REG(chip, I2S_MODE)); - /* interrupt setup - unmask MPU, PLAYBACK & CAPTURE */ + /* interrupt setup */ cmdw = inw(FM801_REG(chip, IRQ_MASK)); - cmdw &= ~0x0083; + if (chip->irq < 0) + cmdw |= 0x00c3; /* mask everything, no PCM nor MPU */ + else + cmdw &= ~0x0083; /* unmask MPU, PLAYBACK & CAPTURE */ outw(cmdw, FM801_REG(chip, IRQ_MASK)); /* interrupt clear */ @@ -1365,20 +1387,23 @@ static int __devinit snd_fm801_create(struct snd_card *card, chip->card = card; chip->pci = pci; chip->irq = -1; + chip->tea575x_tuner = tea575x_tuner; if ((err = pci_request_regions(pci, "FM801")) < 0) { kfree(chip); pci_disable_device(pci); return err; } chip->port = pci_resource_start(pci, 0); - if (request_irq(pci->irq, snd_fm801_interrupt, SA_INTERRUPT|SA_SHIRQ, - "FM801", chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq); - snd_fm801_free(chip); - return -EBUSY; + 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); } - chip->irq = pci->irq; - pci_set_master(pci); pci_read_config_byte(pci, PCI_REVISION_ID, &rev); if (rev >= 0xb1) /* FM801-AU */ @@ -1394,12 +1419,12 @@ 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 & 0xffff) < 4) { + if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 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 & 0xffff) - 1]; + chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1]; snd_tea575x_init(&chip->tea); } #endif @@ -1439,6 +1464,9 @@ 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) + goto __fm801_tuner_only; + if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); return err; @@ -1465,6 +1493,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, return err; } + __fm801_tuner_only: if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; @@ -1502,9 +1531,9 @@ static int snd_fm801_suspend(struct pci_dev *pci, pm_message_t state) chip->saved_regs[i] = inw(chip->port + saved_regs[i]); /* FIXME: tea575x suspend */ - pci_set_power_state(pci, PCI_D3hot); pci_disable_device(pci); pci_save_state(pci); + pci_set_power_state(pci, pci_choose_state(pci, state)); return 0; } @@ -1514,9 +1543,14 @@ static int snd_fm801_resume(struct pci_dev *pci) struct fm801 *chip = card->private_data; int i; - pci_restore_state(pci); - pci_enable_device(pci); pci_set_power_state(pci, PCI_D0); + pci_restore_state(pci); + if (pci_enable_device(pci) < 0) { + printk(KERN_ERR "fm801: pci_enable_device failed, " + "disabling device\n"); + snd_card_disconnect(card); + return -EIO; + } pci_set_master(pci); snd_fm801_chip_init(chip, 1);