atomic: use <linux/atomic.h>
[linux-2.6.git] / sound / pci / bt87x.c
index c5557ea..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>
@@ -44,7 +43,7 @@ MODULE_SUPPORTED_DEVICE("{{Brooktree,Bt878},"
 static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
-static int digital_rate[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* digital input rate */
+static int digital_rate[SNDRV_CARDS];  /* digital input rate */
 static int load_all;   /* allow to load the non-whitelisted cards */
 
 module_param_array(index, int, NULL, 0444);
@@ -59,16 +58,6 @@ module_param(load_all, bool, 0444);
 MODULE_PARM_DESC(load_all, "Allow to load the non-whitelisted cards");
 
 
-#ifndef PCI_VENDOR_ID_BROOKTREE
-#define PCI_VENDOR_ID_BROOKTREE 0x109e
-#endif
-#ifndef PCI_DEVICE_ID_BROOKTREE_878
-#define PCI_DEVICE_ID_BROOKTREE_878 0x0878
-#endif
-#ifndef PCI_DEVICE_ID_BROOKTREE_879
-#define PCI_DEVICE_ID_BROOKTREE_879 0x0879
-#endif
-
 /* register offsets */
 #define REG_INT_STAT           0x100   /* interrupt status */
 #define REG_INT_MASK           0x104   /* interrupt mask */
@@ -157,19 +146,59 @@ 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)
 
-typedef struct snd_bt87x bt87x_t;
+/* 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 {
-       snd_card_t *card;
+       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;
-       long opened;
-       snd_pcm_substream_t *substream;
+       unsigned long opened;
+       struct snd_pcm_substream *substream;
 
        struct snd_dma_buffer dma_risc;
        unsigned int line_bytes;
@@ -185,20 +214,19 @@ struct snd_bt87x {
 
 enum { DEVICE_DIGITAL, DEVICE_ANALOG };
 
-static inline u32 snd_bt87x_readl(bt87x_t *chip, u32 reg)
+static inline u32 snd_bt87x_readl(struct snd_bt87x *chip, u32 reg)
 {
        return readl(chip->mmio + reg);
 }
 
-static inline void snd_bt87x_writel(bt87x_t *chip, u32 reg, u32 value)
+static inline void snd_bt87x_writel(struct snd_bt87x *chip, u32 reg, u32 value)
 {
        writel(value, chip->mmio + reg);
 }
 
-static int snd_bt87x_create_risc(bt87x_t *chip, snd_pcm_substream_t *substream,
+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;
 
@@ -217,6 +245,7 @@ static int snd_bt87x_create_risc(bt87x_t *chip, snd_pcm_substream_t *substream,
                rest = period_bytes;
                do {
                        u32 cmd, len;
+                       unsigned int addr;
 
                        len = PAGE_SIZE - (offset % PAGE_SIZE);
                        if (len > rest)
@@ -231,7 +260,8 @@ static int snd_bt87x_create_risc(bt87x_t *chip, snd_pcm_substream_t *substream,
                        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);
@@ -245,7 +275,7 @@ static int snd_bt87x_create_risc(bt87x_t *chip, snd_pcm_substream_t *substream,
        return 0;
 }
 
-static void snd_bt87x_free_risc(bt87x_t *chip)
+static void snd_bt87x_free_risc(struct snd_bt87x *chip)
 {
        if (chip->dma_risc.area) {
                snd_dma_free_pages(&chip->dma_risc);
@@ -253,7 +283,7 @@ static void snd_bt87x_free_risc(bt87x_t *chip)
        }
 }
 
-static void snd_bt87x_pci_error(bt87x_t *chip, unsigned int status)
+static void snd_bt87x_pci_error(struct snd_bt87x *chip, unsigned int status)
 {
        u16 pci_status;
 
@@ -280,9 +310,9 @@ static void snd_bt87x_pci_error(bt87x_t *chip, unsigned int status)
        }
 }
 
-static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id)
 {
-       bt87x_t *chip = dev_id;
+       struct snd_bt87x *chip = dev_id;
        unsigned int status, irq_status;
 
        status = snd_bt87x_readl(chip, REG_INT_STAT);
@@ -315,11 +345,12 @@ static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id, struct pt_regs *re
        return IRQ_HANDLED;
 }
 
-static snd_pcm_hardware_t snd_bt87x_digital_hw = {
+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,
@@ -331,11 +362,12 @@ static snd_pcm_hardware_t snd_bt87x_digital_hw = {
        .periods_max = 255,
 };
 
-static snd_pcm_hardware_t snd_bt87x_analog_hw = {
+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,
@@ -349,58 +381,39 @@ static snd_pcm_hardware_t snd_bt87x_analog_hw = {
        .periods_max = 255,
 };
 
-static int snd_bt87x_set_digital_hw(bt87x_t *chip, snd_pcm_runtime_t *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;
+static int snd_bt87x_set_digital_hw(struct snd_bt87x *chip, struct snd_pcm_runtime *runtime)
+{
+       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;
 }
 
-static int snd_bt87x_set_analog_hw(bt87x_t *chip, snd_pcm_runtime_t *runtime)
+static int snd_bt87x_set_analog_hw(struct snd_bt87x *chip, struct snd_pcm_runtime *runtime)
 {
-       static ratnum_t analog_clock = {
+       static struct snd_ratnum analog_clock = {
                .num = ANALOG_CLOCK,
                .den_min = CLOCK_DIV_MIN,
                .den_max = CLOCK_DIV_MAX,
                .den_step = 1
        };
-       static snd_pcm_hw_constraint_ratnums_t constraint_rates = {
+       static struct snd_pcm_hw_constraint_ratnums constraint_rates = {
                .nrats = 1,
                .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);
 }
 
-static int snd_bt87x_pcm_open(snd_pcm_substream_t *substream)
+static int snd_bt87x_pcm_open(struct snd_pcm_substream *substream)
 {
-       bt87x_t *chip = snd_pcm_substream_chip(substream);
-       snd_pcm_runtime_t *runtime = substream->runtime;
+       struct snd_bt87x *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
        int err;
 
        if (test_and_set_bit(0, &chip->opened))
@@ -426,9 +439,14 @@ _error:
        return err;
 }
 
-static int snd_bt87x_close(snd_pcm_substream_t *substream)
+static int snd_bt87x_close(struct snd_pcm_substream *substream)
 {
-       bt87x_t *chip = snd_pcm_substream_chip(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);
@@ -436,10 +454,10 @@ static int snd_bt87x_close(snd_pcm_substream_t *substream)
        return 0;
 }
 
-static int snd_bt87x_hw_params(snd_pcm_substream_t *substream,
-                              snd_pcm_hw_params_t *hw_params)
+static int snd_bt87x_hw_params(struct snd_pcm_substream *substream,
+                              struct snd_pcm_hw_params *hw_params)
 {
-       bt87x_t *chip = snd_pcm_substream_chip(substream);
+       struct snd_bt87x *chip = snd_pcm_substream_chip(substream);
        int err;
 
        err = snd_pcm_lib_malloc_pages(substream,
@@ -451,19 +469,19 @@ static int snd_bt87x_hw_params(snd_pcm_substream_t *substream,
                                     params_period_bytes(hw_params));
 }
 
-static int snd_bt87x_hw_free(snd_pcm_substream_t *substream)
+static int snd_bt87x_hw_free(struct snd_pcm_substream *substream)
 {
-       bt87x_t *chip = snd_pcm_substream_chip(substream);
+       struct snd_bt87x *chip = snd_pcm_substream_chip(substream);
 
        snd_bt87x_free_risc(chip);
        snd_pcm_lib_free_pages(substream);
        return 0;
 }
 
-static int snd_bt87x_prepare(snd_pcm_substream_t *substream)
+static int snd_bt87x_prepare(struct snd_pcm_substream *substream)
 {
-       bt87x_t *chip = snd_pcm_substream_chip(substream);
-       snd_pcm_runtime_t *runtime = substream->runtime;
+       struct snd_bt87x *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
        int decimation;
 
        spin_lock_irq(&chip->reg_lock);
@@ -477,7 +495,7 @@ static int snd_bt87x_prepare(snd_pcm_substream_t *substream)
        return 0;
 }
 
-static int snd_bt87x_start(bt87x_t *chip)
+static int snd_bt87x_start(struct snd_bt87x *chip)
 {
        spin_lock(&chip->reg_lock);
        chip->current_line = 0;
@@ -491,7 +509,7 @@ static int snd_bt87x_start(bt87x_t *chip)
        return 0;
 }
 
-static int snd_bt87x_stop(bt87x_t *chip)
+static int snd_bt87x_stop(struct snd_bt87x *chip)
 {
        spin_lock(&chip->reg_lock);
        chip->reg_control &= ~(CTL_FIFO_ENABLE | CTL_RISC_ENABLE | CTL_ACAP_EN);
@@ -502,9 +520,9 @@ static int snd_bt87x_stop(bt87x_t *chip)
        return 0;
 }
 
-static int snd_bt87x_trigger(snd_pcm_substream_t *substream, int cmd)
+static int snd_bt87x_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-       bt87x_t *chip = snd_pcm_substream_chip(substream);
+       struct snd_bt87x *chip = snd_pcm_substream_chip(substream);
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -516,15 +534,15 @@ static int snd_bt87x_trigger(snd_pcm_substream_t *substream, int cmd)
        }
 }
 
-static snd_pcm_uframes_t snd_bt87x_pointer(snd_pcm_substream_t *substream)
+static snd_pcm_uframes_t snd_bt87x_pointer(struct snd_pcm_substream *substream)
 {
-       bt87x_t *chip = snd_pcm_substream_chip(substream);
-       snd_pcm_runtime_t *runtime = substream->runtime;
+       struct snd_bt87x *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
 
        return (snd_pcm_uframes_t)bytes_to_frames(runtime, chip->current_line * chip->line_bytes);
 }
 
-static snd_pcm_ops_t snd_bt87x_pcm_ops = {
+static struct snd_pcm_ops snd_bt87x_pcm_ops = {
        .open = snd_bt87x_pcm_open,
        .close = snd_bt87x_close,
        .ioctl = snd_pcm_lib_ioctl,
@@ -536,7 +554,8 @@ static snd_pcm_ops_t snd_bt87x_pcm_ops = {
        .page = snd_pcm_sgbuf_ops_page,
 };
 
-static int snd_bt87x_capture_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info)
+static int snd_bt87x_capture_volume_info(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_info *info)
 {
        info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        info->count = 1;
@@ -545,17 +564,19 @@ static int snd_bt87x_capture_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_
        return 0;
 }
 
-static int snd_bt87x_capture_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+static int snd_bt87x_capture_volume_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *value)
 {
-       bt87x_t *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol);
 
        value->value.integer.value[0] = (chip->reg_control & CTL_A_GAIN_MASK) >> CTL_A_GAIN_SHIFT;
        return 0;
 }
 
-static int snd_bt87x_capture_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+static int snd_bt87x_capture_volume_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *value)
 {
-       bt87x_t *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol);
        u32 old_control;
        int changed;
 
@@ -569,7 +590,7 @@ static int snd_bt87x_capture_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_v
        return changed;
 }
 
-static snd_kcontrol_new_t snd_bt87x_capture_volume = {
+static struct snd_kcontrol_new snd_bt87x_capture_volume = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Capture Volume",
        .info = snd_bt87x_capture_volume_info,
@@ -577,26 +598,21 @@ static snd_kcontrol_new_t snd_bt87x_capture_volume = {
        .put = snd_bt87x_capture_volume_put,
 };
 
-static int snd_bt87x_capture_boost_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info)
-{
-       info->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-       info->count = 1;
-       info->value.integer.min = 0;
-       info->value.integer.max = 1;
-       return 0;
-}
+#define snd_bt87x_capture_boost_info   snd_ctl_boolean_mono_info
 
-static int snd_bt87x_capture_boost_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+static int snd_bt87x_capture_boost_get(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *value)
 {
-       bt87x_t *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol);
 
        value->value.integer.value[0] = !! (chip->reg_control & CTL_A_G2X);
        return 0;
 }
 
-static int snd_bt87x_capture_boost_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+static int snd_bt87x_capture_boost_put(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *value)
 {
-       bt87x_t *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol);
        u32 old_control;
        int changed;
 
@@ -610,7 +626,7 @@ static int snd_bt87x_capture_boost_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_va
        return changed;
 }
 
-static snd_kcontrol_new_t snd_bt87x_capture_boost = {
+static struct snd_kcontrol_new snd_bt87x_capture_boost = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Capture Boost",
        .info = snd_bt87x_capture_boost_info,
@@ -618,30 +634,27 @@ static snd_kcontrol_new_t snd_bt87x_capture_boost = {
        .put = snd_bt87x_capture_boost_put,
 };
 
-static int snd_bt87x_capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info)
+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(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+static int snd_bt87x_capture_source_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *value)
 {
-       bt87x_t *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol);
 
        value->value.enumerated.item[0] = (chip->reg_control & CTL_A_SEL_MASK) >> CTL_A_SEL_SHIFT;
        return 0;
 }
 
-static int snd_bt87x_capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+static int snd_bt87x_capture_source_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *value)
 {
-       bt87x_t *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol);
        u32 old_control;
        int changed;
 
@@ -655,7 +668,7 @@ static int snd_bt87x_capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_v
        return changed;
 }
 
-static snd_kcontrol_new_t snd_bt87x_capture_source = {
+static struct snd_kcontrol_new snd_bt87x_capture_source = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Capture Source",
        .info = snd_bt87x_capture_source_info,
@@ -663,33 +676,30 @@ static snd_kcontrol_new_t snd_bt87x_capture_source = {
        .put = snd_bt87x_capture_source_put,
 };
 
-static int snd_bt87x_free(bt87x_t *chip)
+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);
        return 0;
 }
 
-static int snd_bt87x_dev_free(snd_device_t *device)
+static int snd_bt87x_dev_free(struct snd_device *device)
 {
-       bt87x_t *chip = device->device_data;
+       struct snd_bt87x *chip = device->device_data;
        return snd_bt87x_free(chip);
 }
 
-static int __devinit snd_bt87x_pcm(bt87x_t *chip, int device, char *name)
+static int __devinit snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *name)
 {
        int err;
-       snd_pcm_t *pcm;
+       struct snd_pcm *pcm;
 
        err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
        if (err < 0)
@@ -701,16 +711,16 @@ static int __devinit snd_bt87x_pcm(bt87x_t *chip, int device, char *name)
                                                     SNDRV_DMA_TYPE_DEV_SG,
                                                     snd_dma_pci_data(chip->pci),
                                                        128 * 1024,
-                                                       (255 * 4092 + 1023) & ~1023);
+                                                       ALIGN(255 * 4092, 1024));
 }
 
-static int __devinit snd_bt87x_create(snd_card_t *card,
+static int __devinit snd_bt87x_create(struct snd_card *card,
                                      struct pci_dev *pci,
-                                     bt87x_t **rchip)
+                                     struct snd_bt87x **rchip)
 {
-       bt87x_t *chip;
+       struct snd_bt87x *chip;
        int err;
-       static snd_device_ops_t ops = {
+       static struct snd_device_ops ops = {
                .dev_free = snd_bt87x_dev_free
        };
 
@@ -720,7 +730,7 @@ static int __devinit snd_bt87x_create(snd_card_t *card,
        if (err < 0)
                return err;
 
-       chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        if (!chip) {
                pci_disable_device(pci);
                return -ENOMEM;
@@ -735,51 +745,75 @@ static int __devinit snd_bt87x_create(snd_card_t *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, SA_INTERRUPT | SA_SHIRQ,
-                       "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 = PCI_DEVICE_ID_BROOKTREE_##chip, \
+         .device = chip, \
          .subvendor = subvend, .subdevice = subdev, \
-         .driver_data = rate }
-
-/* driver_data is the default digital_rate value for that device */
-static struct pci_device_id snd_bt87x_ids[] = {
-       BT_DEVICE(878, 0x0070, 0x13eb, 32000), /* Hauppauge WinTV series */
-       BT_DEVICE(879, 0x0070, 0x13eb, 32000), /* Hauppauge WinTV series */
-       BT_DEVICE(878, 0x0070, 0xff01, 44100), /* Viewcast Osprey 200 */
+         .driver_data = SND_BT87X_BOARD_ ## id }
+/* driver_data is the card id for that device */
+
+static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_ids) = {
+       /* Hauppauge WinTV series */
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, GENERIC),
+       /* Hauppauge WinTV series */
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, GENERIC),
+       /* Viewcast Osprey 200 */
+       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, OSPREY440),
+       /* ATI TV-Wonder */
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1002, 0x0001, GENERIC),
+       /* Leadtek Winfast tv 2000xp delux */
+       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, 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, 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);
@@ -790,54 +824,62 @@ static struct {
        unsigned short subvendor, subdevice;
 } blacklist[] __devinitdata = {
        {0x0071, 0x0101}, /* Nebula Electronics DigiTV */
+       {0x11bd, 0x001c}, /* Pinnacle PCTV Sat */
        {0x11bd, 0x0026}, /* Pinnacle PCTV SAT CI */
        {0x1461, 0x0761}, /* AVermedia AverTV DVB-T */
        {0x1461, 0x0771}, /* AVermedia DVB-T 771 */
        {0x1822, 0x0001}, /* Twinhan VisionPlus DVB-T */
+       {0x18ac, 0xd500}, /* DVICO FusionHDTV 5 Lite */
        {0x18ac, 0xdb10}, /* DVICO FusionHDTV DVB-T Lite */
+       {0x18ac, 0xdb11}, /* Ultraview DVB-T Lite */
        {0x270f, 0xfc00}, /* Chaintech Digitop DST-1000 DVB-S */
+       {0x7063, 0x2000}, /* pcHDTV HD-2000 TV */
 };
 
 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);
-       if (supported)
+       supported = pci_match_id(snd_bt87x_ids, pci);
+       if (supported && supported->driver_data > 0)
                return supported->driver_data;
 
        for (i = 0; i < ARRAY_SIZE(blacklist); ++i)
                if (blacklist[i].subvendor == pci->subsystem_vendor &&
                    blacklist[i].subdevice == pci->subsystem_device) {
-                       snd_printdd(KERN_INFO "card %#04x:%#04x has no audio\n",
-                                   pci->subsystem_vendor, pci->subsystem_device);
+                       snd_printdd(KERN_INFO "card %#04x-%#04x:%#04x has no audio\n",
+                                   pci->device, pci->subsystem_vendor, pci->subsystem_device);
                        return -EBUSY;
                }
 
-       snd_printk(KERN_INFO "unknown card %#04x:%#04x, using default rate 32000\n",
-                  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@lists.sf.net>\n");
-       return 32000; /* default rate */
+                  "<alsa-devel@alsa-project.org>\n");
+       return SND_BT87X_BOARD_UNKNOWN;
 }
 
 static int __devinit snd_bt87x_probe(struct pci_dev *pci,
                                     const struct pci_device_id *pci_id)
 {
        static int dev;
-       snd_card_t *card;
-       bt87x_t *chip;
-       int err, rate;
+       struct snd_card *card;
+       struct snd_bt87x *chip;
+       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;
@@ -846,40 +888,53 @@ 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);
-       sprintf(card->longname, "%s at %#lx, irq %i",
-               card->shortname, pci_resource_start(pci, 0), chip->irq);
+       sprintf(card->longname, "%s at %#llx, irq %i",
+               card->shortname, (unsigned long long)pci_resource_start(pci, 0),
+               chip->irq);
        strcpy(card->mixername, "Bt87x");
 
        err = snd_card_register(card);
@@ -903,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[] = {
-       BT_DEVICE(878, PCI_ANY_ID, PCI_ANY_ID, 0),
-       BT_DEVICE(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),