atomic: use <linux/atomic.h>
[linux-2.6.git] / sound / pci / bt87x.c
index f0e1298..3918033 100644 (file)
@@ -21,7 +21,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
@@ -147,15 +146,56 @@ MODULE_PARM_DESC(load_all, "Allow to load the non-whitelisted cards");
 /* SYNC, one WRITE per line, one extra WRITE per page boundary, SYNC, JUMP */
 #define MAX_RISC_SIZE ((1 + 255 + (PAGE_ALIGN(255 * 4092) / PAGE_SIZE - 1) + 1 + 1) * 8)
 
+/* Cards with configuration information */
+enum snd_bt87x_boardid {
+       SND_BT87X_BOARD_UNKNOWN,
+       SND_BT87X_BOARD_GENERIC,        /* both an & dig interfaces, 32kHz */
+       SND_BT87X_BOARD_ANALOG,         /* board with no external A/D */
+       SND_BT87X_BOARD_OSPREY2x0,
+       SND_BT87X_BOARD_OSPREY440,
+       SND_BT87X_BOARD_AVPHONE98,
+};
+
+/* Card configuration */
+struct snd_bt87x_board {
+       int dig_rate;           /* Digital input sampling rate */
+       u32 digital_fmt;        /* Register settings for digital input */
+       unsigned no_analog:1;   /* No analog input */
+       unsigned no_digital:1;  /* No digital input */
+};
+
+static __devinitdata struct snd_bt87x_board snd_bt87x_boards[] = {
+       [SND_BT87X_BOARD_UNKNOWN] = {
+               .dig_rate = 32000, /* just a guess */
+       },
+       [SND_BT87X_BOARD_GENERIC] = {
+               .dig_rate = 32000,
+       },
+       [SND_BT87X_BOARD_ANALOG] = {
+               .no_digital = 1,
+       },
+       [SND_BT87X_BOARD_OSPREY2x0] = {
+               .dig_rate = 44100,
+               .digital_fmt = CTL_DA_LRI | (1 << CTL_DA_LRD_SHIFT),
+       },
+       [SND_BT87X_BOARD_OSPREY440] = {
+               .dig_rate = 32000,
+               .digital_fmt = CTL_DA_LRI | (1 << CTL_DA_LRD_SHIFT),
+               .no_analog = 1,
+       },
+       [SND_BT87X_BOARD_AVPHONE98] = {
+               .dig_rate = 48000,
+       },
+};
+
 struct snd_bt87x {
        struct snd_card *card;
        struct pci_dev *pci;
+       struct snd_bt87x_board board;
 
        void __iomem *mmio;
        int irq;
 
-       int dig_rate;
-
        spinlock_t reg_lock;
        unsigned long opened;
        struct snd_pcm_substream *substream;
@@ -187,7 +227,6 @@ static inline void snd_bt87x_writel(struct snd_bt87x *chip, u32 reg, u32 value)
 static int snd_bt87x_create_risc(struct snd_bt87x *chip, struct snd_pcm_substream *substream,
                                 unsigned int periods, unsigned int period_bytes)
 {
-       struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
        unsigned int i, offset;
        u32 *risc;
 
@@ -206,6 +245,7 @@ static int snd_bt87x_create_risc(struct snd_bt87x *chip, struct snd_pcm_substrea
                rest = period_bytes;
                do {
                        u32 cmd, len;
+                       unsigned int addr;
 
                        len = PAGE_SIZE - (offset % PAGE_SIZE);
                        if (len > rest)
@@ -220,7 +260,8 @@ static int snd_bt87x_create_risc(struct snd_bt87x *chip, struct snd_pcm_substrea
                        if (len == rest)
                                cmd |= RISC_EOL | RISC_IRQ;
                        *risc++ = cpu_to_le32(cmd);
-                       *risc++ = cpu_to_le32((u32)snd_pcm_sgbuf_get_addr(sgbuf, offset));
+                       addr = snd_pcm_sgbuf_get_addr(substream, offset);
+                       *risc++ = cpu_to_le32(addr);
                        offset += len;
                        rest -= len;
                } while (rest > 0);
@@ -308,7 +349,8 @@ static struct snd_pcm_hardware snd_bt87x_digital_hw = {
        .info = SNDRV_PCM_INFO_MMAP |
                SNDRV_PCM_INFO_INTERLEAVED |
                SNDRV_PCM_INFO_BLOCK_TRANSFER |
-               SNDRV_PCM_INFO_MMAP_VALID,
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_BATCH,
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
        .rates = 0, /* set at runtime */
        .channels_min = 2,
@@ -324,7 +366,8 @@ static struct snd_pcm_hardware snd_bt87x_analog_hw = {
        .info = SNDRV_PCM_INFO_MMAP |
                SNDRV_PCM_INFO_INTERLEAVED |
                SNDRV_PCM_INFO_BLOCK_TRANSFER |
-               SNDRV_PCM_INFO_MMAP_VALID,
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_BATCH,
        .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
        .rates = SNDRV_PCM_RATE_KNOT,
        .rate_min = ANALOG_CLOCK / CLOCK_DIV_MAX,
@@ -340,30 +383,11 @@ static struct snd_pcm_hardware snd_bt87x_analog_hw = {
 
 static int snd_bt87x_set_digital_hw(struct snd_bt87x *chip, struct snd_pcm_runtime *runtime)
 {
-       static struct {
-               int rate;
-               unsigned int bit;
-       } ratebits[] = {
-               {8000, SNDRV_PCM_RATE_8000},
-               {11025, SNDRV_PCM_RATE_11025},
-               {16000, SNDRV_PCM_RATE_16000},
-               {22050, SNDRV_PCM_RATE_22050},
-               {32000, SNDRV_PCM_RATE_32000},
-               {44100, SNDRV_PCM_RATE_44100},
-               {48000, SNDRV_PCM_RATE_48000}
-       };
-       int i;
-
-       chip->reg_control |= CTL_DA_IOM_DA;
+       chip->reg_control |= CTL_DA_IOM_DA | CTL_A_PWRDN;
        runtime->hw = snd_bt87x_digital_hw;
-       runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
-       for (i = 0; i < ARRAY_SIZE(ratebits); ++i)
-               if (chip->dig_rate == ratebits[i].rate) {
-                       runtime->hw.rates = ratebits[i].bit;
-                       break;
-               }
-       runtime->hw.rate_min = chip->dig_rate;
-       runtime->hw.rate_max = chip->dig_rate;
+       runtime->hw.rates = snd_pcm_rate_to_rate_bit(chip->board.dig_rate);
+       runtime->hw.rate_min = chip->board.dig_rate;
+       runtime->hw.rate_max = chip->board.dig_rate;
        return 0;
 }
 
@@ -380,7 +404,7 @@ static int snd_bt87x_set_analog_hw(struct snd_bt87x *chip, struct snd_pcm_runtim
                .rats = &analog_clock
        };
 
-       chip->reg_control &= ~CTL_DA_IOM_DA;
+       chip->reg_control &= ~(CTL_DA_IOM_DA | CTL_A_PWRDN);
        runtime->hw = snd_bt87x_analog_hw;
        return snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
                                             &constraint_rates);
@@ -419,6 +443,11 @@ static int snd_bt87x_close(struct snd_pcm_substream *substream)
 {
        struct snd_bt87x *chip = snd_pcm_substream_chip(substream);
 
+       spin_lock_irq(&chip->reg_lock);
+       chip->reg_control |= CTL_A_PWRDN;
+       snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
+       spin_unlock_irq(&chip->reg_lock);
+
        chip->substream = NULL;
        clear_bit(0, &chip->opened);
        smp_mb__after_clear_bit();
@@ -608,15 +637,9 @@ static struct snd_kcontrol_new snd_bt87x_capture_boost = {
 static int snd_bt87x_capture_source_info(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_info *info)
 {
-       static char *texts[3] = {"TV Tuner", "FM", "Mic/Line"};
+       static const char *const texts[3] = {"TV Tuner", "FM", "Mic/Line"};
 
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = 3;
-       if (info->value.enumerated.item > 2)
-               info->value.enumerated.item = 2;
-       strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]);
-       return 0;
+       return snd_ctl_enum_info(info, 1, 3, texts);
 }
 
 static int snd_bt87x_capture_source_get(struct snd_kcontrol *kcontrol,
@@ -655,15 +678,12 @@ static struct snd_kcontrol_new snd_bt87x_capture_source = {
 
 static int snd_bt87x_free(struct snd_bt87x *chip)
 {
-       if (chip->mmio) {
+       if (chip->mmio)
                snd_bt87x_stop(chip);
-               if (chip->irq >= 0)
-                       synchronize_irq(chip->irq);
-
-               iounmap(chip->mmio);
-       }
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
+       if (chip->mmio)
+               iounmap(chip->mmio);
        pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
        kfree(chip);
@@ -725,64 +745,75 @@ static int __devinit snd_bt87x_create(struct snd_card *card,
                pci_disable_device(pci);
                return err;
        }
-       chip->mmio = ioremap_nocache(pci_resource_start(pci, 0),
-                                    pci_resource_len(pci, 0));
+       chip->mmio = pci_ioremap_bar(pci, 0);
        if (!chip->mmio) {
-               snd_bt87x_free(chip);
                snd_printk(KERN_ERR "cannot remap io memory\n");
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto fail;
        }
 
-       chip->reg_control = CTL_DA_ES2 | CTL_PKTP_16 | (15 << CTL_DA_SDR_SHIFT);
+       chip->reg_control = CTL_A_PWRDN | CTL_DA_ES2 |
+                           CTL_PKTP_16 | (15 << CTL_DA_SDR_SHIFT);
        chip->interrupt_mask = MY_INTERRUPTS;
        snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
        snd_bt87x_writel(chip, REG_INT_MASK, 0);
        snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS);
 
-       if (request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED,
-                       "Bt87x audio", chip)) {
-               snd_bt87x_free(chip);
-               snd_printk(KERN_ERR "cannot grab irq\n");
-               return -EBUSY;
+       err = request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED,
+                         KBUILD_MODNAME, chip);
+       if (err < 0) {
+               snd_printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
+               goto fail;
        }
        chip->irq = pci->irq;
        pci_set_master(pci);
        synchronize_irq(chip->irq);
 
        err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
-       if (err < 0) {
-               snd_bt87x_free(chip);
-               return err;
-       }
+       if (err < 0)
+               goto fail;
+
        snd_card_set_dev(card, &pci->dev);
        *rchip = chip;
        return 0;
+
+fail:
+       snd_bt87x_free(chip);
+       return err;
 }
 
-#define BT_DEVICE(chip, subvend, subdev, rate) \
+#define BT_DEVICE(chip, subvend, subdev, id) \
        { .vendor = PCI_VENDOR_ID_BROOKTREE, \
          .device = chip, \
          .subvendor = subvend, .subdevice = subdev, \
-         .driver_data = rate }
+         .driver_data = SND_BT87X_BOARD_ ## id }
+/* driver_data is the card id for that device */
 
-/* driver_data is the default digital_rate value for that device */
-static struct pci_device_id snd_bt87x_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_ids) = {
        /* Hauppauge WinTV series */
-       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, 32000),
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, GENERIC),
        /* Hauppauge WinTV series */
-       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, 32000),
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, GENERIC),
        /* Viewcast Osprey 200 */
-       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, 44100),
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, OSPREY2x0),
        /* Viewcast Osprey 440 (rate is configurable via gpio) */
-       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff07, 32000),
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff07, OSPREY440),
        /* ATI TV-Wonder */
-       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1002, 0x0001, 32000),
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1002, 0x0001, GENERIC),
        /* Leadtek Winfast tv 2000xp delux */
-       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, 32000),
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, GENERIC),
+       /* Pinnacle PCTV */
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x11bd, 0x0012, GENERIC),
        /* Voodoo TV 200 */
-       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, 32000),
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, GENERIC),
+       /* Askey Computer Corp. MagicTView'99 */
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x144f, 0x3000, GENERIC),
        /* AVerMedia Studio No. 103, 203, ...? */
-       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, 48000),
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, AVPHONE98),
+       /* Prolink PixelView PV-M4900 */
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1554, 0x4011, GENERIC),
+       /* Pinnacle  Studio PCTV rave */
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0xbd11, 0x1200, GENERIC),
        { }
 };
 MODULE_DEVICE_TABLE(pci, snd_bt87x_ids);
@@ -807,13 +838,13 @@ static struct {
 
 static struct pci_driver driver;
 
-/* return the rate of the card, or a negative value if it's blacklisted */
+/* return the id of the card, or a negative value if it's blacklisted */
 static int __devinit snd_bt87x_detect_card(struct pci_dev *pci)
 {
        int i;
        const struct pci_device_id *supported;
 
-       supported = pci_match_device(&driver, pci);
+       supported = pci_match_id(snd_bt87x_ids, pci);
        if (supported && supported->driver_data > 0)
                return supported->driver_data;
 
@@ -825,12 +856,12 @@ static int __devinit snd_bt87x_detect_card(struct pci_dev *pci)
                        return -EBUSY;
                }
 
-       snd_printk(KERN_INFO "unknown card %#04x-%#04x:%#04x, using default rate 32000\n",
-                  pci->device, pci->subsystem_vendor, pci->subsystem_device);
+       snd_printk(KERN_INFO "unknown card %#04x-%#04x:%#04x\n",
+                  pci->device, pci->subsystem_vendor, pci->subsystem_device);
        snd_printk(KERN_DEBUG "please mail id, board name, and, "
                   "if it works, the correct digital_rate option to "
                   "<alsa-devel@alsa-project.org>\n");
-       return 32000; /* default rate */
+       return SND_BT87X_BOARD_UNKNOWN;
 }
 
 static int __devinit snd_bt87x_probe(struct pci_dev *pci,
@@ -839,12 +870,16 @@ static int __devinit snd_bt87x_probe(struct pci_dev *pci,
        static int dev;
        struct snd_card *card;
        struct snd_bt87x *chip;
-       int err, rate;
+       int err;
+       enum snd_bt87x_boardid boardid;
 
-       rate = pci_id->driver_data;
-       if (! rate)
-               if ((rate = snd_bt87x_detect_card(pci)) <= 0)
+       if (!pci_id->driver_data) {
+               err = snd_bt87x_detect_card(pci);
+               if (err < 0)
                        return -ENODEV;
+               boardid = err;
+       } else
+               boardid = pci_id->driver_data;
 
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
@@ -853,35 +888,47 @@ static int __devinit snd_bt87x_probe(struct pci_dev *pci,
                return -ENOENT;
        }
 
-       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
-       if (!card)
-               return -ENOMEM;
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        err = snd_bt87x_create(card, pci, &chip);
        if (err < 0)
                goto _error;
 
-       if (digital_rate[dev] > 0)
-               chip->dig_rate = digital_rate[dev];
-       else
-               chip->dig_rate = rate;
+       memcpy(&chip->board, &snd_bt87x_boards[boardid], sizeof(chip->board));
 
-       err = snd_bt87x_pcm(chip, DEVICE_DIGITAL, "Bt87x Digital");
-       if (err < 0)
-               goto _error;
-       err = snd_bt87x_pcm(chip, DEVICE_ANALOG, "Bt87x Analog");
-       if (err < 0)
-               goto _error;
+       if (!chip->board.no_digital) {
+               if (digital_rate[dev] > 0)
+                       chip->board.dig_rate = digital_rate[dev];
 
-       err = snd_ctl_add(card, snd_ctl_new1(&snd_bt87x_capture_volume, chip));
-       if (err < 0)
-               goto _error;
-       err = snd_ctl_add(card, snd_ctl_new1(&snd_bt87x_capture_boost, chip));
-       if (err < 0)
-               goto _error;
-       err = snd_ctl_add(card, snd_ctl_new1(&snd_bt87x_capture_source, chip));
-       if (err < 0)
-               goto _error;
+               chip->reg_control |= chip->board.digital_fmt;
+
+               err = snd_bt87x_pcm(chip, DEVICE_DIGITAL, "Bt87x Digital");
+               if (err < 0)
+                       goto _error;
+       }
+       if (!chip->board.no_analog) {
+               err = snd_bt87x_pcm(chip, DEVICE_ANALOG, "Bt87x Analog");
+               if (err < 0)
+                       goto _error;
+               err = snd_ctl_add(card, snd_ctl_new1(
+                                 &snd_bt87x_capture_volume, chip));
+               if (err < 0)
+                       goto _error;
+               err = snd_ctl_add(card, snd_ctl_new1(
+                                 &snd_bt87x_capture_boost, chip));
+               if (err < 0)
+                       goto _error;
+               err = snd_ctl_add(card, snd_ctl_new1(
+                                 &snd_bt87x_capture_source, chip));
+               if (err < 0)
+                       goto _error;
+       }
+       snd_printk(KERN_INFO "bt87x%d: Using board %d, %sanalog, %sdigital "
+                  "(rate %d Hz)\n", dev, boardid,
+                  chip->board.no_analog ? "no " : "",
+                  chip->board.no_digital ? "no " : "", chip->board.dig_rate);
 
        strcpy(card->driver, "Bt87x");
        sprintf(card->shortname, "Brooktree Bt%x", pci->device);
@@ -911,14 +958,14 @@ static void __devexit snd_bt87x_remove(struct pci_dev *pci)
 
 /* default entries for all Bt87x cards - it's not exported */
 /* driver_data is set to 0 to call detection */
-static struct pci_device_id snd_bt87x_default_ids[] __devinitdata = {
-       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, 0),
-       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, 0),
+static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = {
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN),
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN),
        { }
 };
 
 static struct pci_driver driver = {
-       .name = "Bt87x",
+       .name = KBUILD_MODNAME,
        .id_table = snd_bt87x_ids,
        .probe = snd_bt87x_probe,
        .remove = __devexit_p(snd_bt87x_remove),