vserver 1.9.5.x5
[linux-2.6.git] / sound / pci / via82xx.c
index fb549ea..5b26b52 100644 (file)
@@ -81,27 +81,26 @@ static long mpu_port[SNDRV_CARDS];
 static int joystick[SNDRV_CARDS];
 #endif
 static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000};
-static int ac97_quirk[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = AC97_TUNE_DEFAULT};
+static char *ac97_quirk[SNDRV_CARDS];
 static int dxs_support[SNDRV_CARDS];
-static int boot_devs;
 
-module_param_array(index, int, boot_devs, 0444);
+module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for VIA 82xx bridge.");
-module_param_array(id, charp, boot_devs, 0444);
+module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for VIA 82xx bridge.");
-module_param_array(enable, bool, boot_devs, 0444);
+module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable audio part of VIA 82xx bridge.");
-module_param_array(mpu_port, long, boot_devs, 0444);
+module_param_array(mpu_port, long, NULL, 0444);
 MODULE_PARM_DESC(mpu_port, "MPU-401 port. (VT82C686x only)");
 #ifdef SUPPORT_JOYSTICK
-module_param_array(joystick, bool, boot_devs, 0444);
+module_param_array(joystick, bool, NULL, 0444);
 MODULE_PARM_DESC(joystick, "Enable joystick. (VT82C686x only)");
 #endif
-module_param_array(ac97_clock, int, boot_devs, 0444);
+module_param_array(ac97_clock, int, NULL, 0444);
 MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
-module_param_array(ac97_quirk, int, boot_devs, 0444);
+module_param_array(ac97_quirk, charp, NULL, 0444);
 MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
-module_param_array(dxs_support, int, boot_devs, 0444);
+module_param_array(dxs_support, int, NULL, 0444);
 MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA)");
 
 
@@ -127,6 +126,7 @@ MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2
 #define VIA_REV_8233           0x30    /* 2 rec, 4 pb, 1 multi-pb, spdif */
 #define VIA_REV_8233A          0x40    /* 1 rec, 1 multi-pb, spdf */
 #define VIA_REV_8235           0x50    /* 2 rec, 4 pb, 1 multi-pb, spdif */
+#define VIA_REV_8237           0x60
 
 /*
  *  Direct registers
@@ -332,6 +332,7 @@ struct via_dev {
        struct snd_via_sg_table *idx_table;
        /* for recovery from the unexpected pointer */
        unsigned int lastpos;
+       unsigned int fragsize;
        unsigned int bufsize;
        unsigned int bufsize2;
 };
@@ -390,7 +391,6 @@ struct _snd_via82xx {
        unsigned int ac97_secondary;    /* secondary AC'97 codec is present */
 
        spinlock_t reg_lock;
-       spinlock_t ac97_lock;
        snd_info_entry_t *proc_entry;
 
 #ifdef SUPPORT_JOYSTICK
@@ -478,6 +478,7 @@ static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
        dev->tbl_entries = idx;
        dev->bufsize = periods * fragsize;
        dev->bufsize2 = dev->bufsize / 2;
+       dev->fragsize = fragsize;
        return 0;
 }
 
@@ -562,10 +563,8 @@ static void snd_via82xx_codec_write(ac97_t *ac97,
        xval <<= VIA_REG_AC97_CODEC_ID_SHIFT;
        xval |= reg << VIA_REG_AC97_CMD_SHIFT;
        xval |= val << VIA_REG_AC97_DATA_SHIFT;
-       spin_lock(&chip->ac97_lock);
        snd_via82xx_codec_xwrite(chip, xval);
        snd_via82xx_codec_ready(chip, ac97->num);
-       spin_unlock(&chip->ac97_lock);
 }
 
 static unsigned short snd_via82xx_codec_read(ac97_t *ac97, unsigned short reg)
@@ -578,10 +577,8 @@ static unsigned short snd_via82xx_codec_read(ac97_t *ac97, unsigned short reg)
        xval |= ac97->num ? VIA_REG_AC97_SECONDARY_VALID : VIA_REG_AC97_PRIMARY_VALID;
        xval |= VIA_REG_AC97_READ;
        xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;
-       spin_lock(&chip->ac97_lock);
        while (1) {
                if (again++ > 3) {
-                       spin_unlock(&chip->ac97_lock);
                        snd_printk(KERN_ERR "codec_read: codec %i is not valid [0x%x]\n", ac97->num, snd_via82xx_codec_xread(chip));
                        return 0xffff;
                }
@@ -593,7 +590,6 @@ static unsigned short snd_via82xx_codec_read(ac97_t *ac97, unsigned short reg)
                        break;
                }
        }
-       spin_unlock(&chip->ac97_lock);
        return val & 0xffff;
 }
 
@@ -623,11 +619,6 @@ static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id, struct pt_regs *
        unsigned int status;
        unsigned int i;
 
-#if 0
-       /* FIXME: does it work on via823x? */
-       if (chip->chip_type != TYPE_VIA686)
-               goto _skip_sgd;
-#endif
        status = inl(VIAREG(chip, SGD_SHADOW));
        if (! (status & chip->intr_mask)) {
                if (chip->rmidi)
@@ -635,7 +626,6 @@ static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id, struct pt_regs *
                        return snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
                return IRQ_NONE;
        }
-// _skip_sgd:
 
        /* check status for each stream */
        spin_lock(&chip->reg_lock);
@@ -712,29 +702,34 @@ static int snd_via82xx_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
 
 static inline unsigned int calc_linear_pos(viadev_t *viadev, unsigned int idx, unsigned int count)
 {
-       unsigned int size, res;
+       unsigned int size, base, res;
 
        size = viadev->idx_table[idx].size;
-       res = viadev->idx_table[idx].offset + size - count;
+       base = viadev->idx_table[idx].offset;
+       res = base + size - count;
 
        /* check the validity of the calculated position */
        if (size < count) {
                snd_printd(KERN_ERR "invalid via82xx_cur_ptr (size = %d, count = %d)\n", (int)size, (int)count);
                res = viadev->lastpos;
-       } else if (check_invalid_pos(viadev, res)) {
+       } else {
+               if (! count) {
+                       /* Some mobos report count = 0 on the DMA boundary,
+                        * i.e. count = size indeed.
+                        * Let's check whether this step is above the expected size.
+                        */
+                       int delta = res - viadev->lastpos;
+                       if (delta < 0)
+                               delta += viadev->bufsize;
+                       if ((unsigned int)delta > viadev->fragsize)
+                               res = base;
+               }
+               if (check_invalid_pos(viadev, res)) {
 #ifdef POINTER_DEBUG
-               printk("fail: idx = %i/%i, lastpos = 0x%x, bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, count = 0x%x\n", idx, viadev->tbl_entries, viadev->lastpos, viadev->bufsize2, viadev->idx_table[idx].offset, viadev->idx_table[idx].size, count);
+                       printk(KERN_DEBUG "fail: idx = %i/%i, lastpos = 0x%x, bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, count = 0x%x\n", idx, viadev->tbl_entries, viadev->lastpos, viadev->bufsize2, viadev->idx_table[idx].offset, viadev->idx_table[idx].size, count);
 #endif
-               if (count && size < count) {
-                       snd_printd(KERN_ERR "invalid via82xx_cur_ptr, using last valid pointer\n");
-                       res = viadev->lastpos;
-               } else {
-                       if (! count)
-                               /* bogus count 0 on the DMA boundary? */
-                               res = viadev->idx_table[idx].offset;
-                       else
-                               /* count register returns full size when end of buffer is reached */
-                               res = viadev->idx_table[idx].offset + size;
+                       /* count register returns full size when end of buffer is reached */
+                       res = base + size;
                        if (check_invalid_pos(viadev, res)) {
                                snd_printd(KERN_ERR "invalid via82xx_cur_ptr (2), using last valid pointer\n");
                                res = viadev->lastpos;
@@ -784,12 +779,20 @@ static snd_pcm_uframes_t snd_via8233_pcm_pointer(snd_pcm_substream_t *substream)
        via82xx_t *chip = snd_pcm_substream_chip(substream);
        viadev_t *viadev = (viadev_t *)substream->runtime->private_data;
        unsigned int idx, count, res;
+       int timeout = 5000;
        
        snd_assert(viadev->tbl_entries, return 0);
        if (!(inb(VIADEV_REG(viadev, OFFSET_STATUS)) & VIA_REG_STAT_ACTIVE))
                return 0;
        spin_lock(&chip->reg_lock);
-       count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT));
+       do {
+               count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT));
+               /* some mobos read 0 count */
+               if ((count & 0xffffff) || ! viadev->running)
+                       break;
+       } while (--timeout);
+       if (! timeout)
+               snd_printd(KERN_ERR "zero position is read\n");
        idx = count >> 24;
        if (idx >= viadev->tbl_entries) {
 #ifdef POINTER_DEBUG
@@ -1547,6 +1550,13 @@ static void snd_via82xx_mixer_free_ac97(ac97_t *ac97)
 }
 
 static struct ac97_quirk ac97_quirks[] = {
+       {
+               .vendor = 0x1106,
+               .device = 0x4161,
+               .codec_id = 0x56494161, /* VT1612A */
+               .name = "Soltek SL-75DRV5",
+               .type = AC97_TUNE_NONE
+       },
        {       /* FIXME: which codec? */
                .vendor = 0x1106,
                .device = 0x4161,
@@ -1592,7 +1602,7 @@ static struct ac97_quirk ac97_quirks[] = {
        { } /* terminator */
 };
 
-static int __devinit snd_via82xx_mixer_new(via82xx_t *chip, int ac97_quirk)
+static int __devinit snd_via82xx_mixer_new(via82xx_t *chip, const char *quirk_override)
 {
        ac97_template_t ac97;
        int err;
@@ -1606,6 +1616,7 @@ static int __devinit snd_via82xx_mixer_new(via82xx_t *chip, int ac97_quirk)
                return err;
        chip->ac97_bus->private_free = snd_via82xx_mixer_free_ac97_bus;
        chip->ac97_bus->clock = chip->ac97_clock;
+       chip->ac97_bus->shared_type = AC97_SHARED_TYPE_VIA;
 
        memset(&ac97, 0, sizeof(ac97));
        ac97.private_data = chip;
@@ -1614,7 +1625,7 @@ static int __devinit snd_via82xx_mixer_new(via82xx_t *chip, int ac97_quirk)
        if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0)
                return err;
 
-       snd_ac97_tune_hardware(chip->ac97, ac97_quirks, ac97_quirk);
+       snd_ac97_tune_hardware(chip->ac97, ac97_quirks, quirk_override);
 
        if (chip->chip_type != TYPE_VIA686) {
                /* use slot 10/11 */
@@ -1633,8 +1644,6 @@ static int snd_via8233_init_misc(via82xx_t *chip, int dev)
        int i, err, caps;
        unsigned char val;
 
-       pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE,
-                             chip->old_legacy & ~(VIA_FUNC_ENABLE_SB|VIA_FUNC_ENABLE_FM));
        caps = chip->chip_type == TYPE_VIA8233A ? 1 : 2;
        for (i = 0; i < caps; i++) {
                snd_via8233_capture_source.index = i;
@@ -1671,7 +1680,6 @@ static int snd_via686_init_misc(via82xx_t *chip, int dev)
        legacy_cfg = chip->old_legacy_cfg;
        legacy |= VIA_FUNC_MIDI_IRQMASK;        /* FIXME: correct? (disable MIDI) */
        legacy &= ~VIA_FUNC_ENABLE_GAME;        /* disable joystick */
-       legacy &= ~(VIA_FUNC_ENABLE_SB|VIA_FUNC_ENABLE_FM);     /* diable SB & FM */
        if (chip->revision >= VIA_REV_686_H) {
                rev_h = 1;
                if (mpu_port[dev] >= 0x200) {   /* force MIDI */
@@ -1909,7 +1917,6 @@ static int snd_via82xx_suspend(snd_card_t *card, unsigned int state)
 
        pci_set_power_state(chip->pci, 3);
        pci_disable_device(chip->pci);
-       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        return 0;
 }
 
@@ -1944,7 +1951,6 @@ static int snd_via82xx_resume(snd_card_t *card, unsigned int state)
        for (i = 0; i < chip->num_devs; i++)
                snd_via82xx_channel_reset(chip, &chip->devs[i]);
 
-       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        return 0;
 }
 #endif /* CONFIG_PM */
@@ -1978,6 +1984,7 @@ static int snd_via82xx_free(via82xx_t *chip)
                pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, chip->old_legacy);
                pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, chip->old_legacy_cfg);
        }
+       pci_disable_device(chip->pci);
        kfree(chip);
        return 0;
 }
@@ -2004,14 +2011,15 @@ static int __devinit snd_via82xx_create(snd_card_t * card,
        if ((err = pci_enable_device(pci)) < 0)
                return err;
 
-       if ((chip = kcalloc(1, sizeof(*chip), GFP_KERNEL)) == NULL)
+       if ((chip = kcalloc(1, sizeof(*chip), GFP_KERNEL)) == NULL) {
+               pci_disable_device(pci);
                return -ENOMEM;
+       }
 
        chip->chip_type = chip_type;
        chip->revision = revision;
 
        spin_lock_init(&chip->reg_lock);
-       spin_lock_init(&chip->ac97_lock);
        spin_lock_init(&chip->rates[0].lock);
        spin_lock_init(&chip->rates[1].lock);
        chip->card = card;
@@ -2020,9 +2028,12 @@ static int __devinit snd_via82xx_create(snd_card_t * card,
 
        pci_read_config_byte(pci, VIA_FUNC_ENABLE, &chip->old_legacy);
        pci_read_config_byte(pci, VIA_PNP_CONTROL, &chip->old_legacy_cfg);
+       pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE,
+                             chip->old_legacy & ~(VIA_FUNC_ENABLE_SB|VIA_FUNC_ENABLE_FM));
 
        if ((err = pci_request_regions(pci, card->driver)) < 0) {
                kfree(chip);
+               pci_disable_device(pci);
                return err;
        }
        chip->port = pci_resource_start(pci, 0);
@@ -2069,6 +2080,7 @@ static struct via823x_info via823x_cards[] __devinitdata = {
        { VIA_REV_8233, "VIA 8233", TYPE_VIA8233 },
        { VIA_REV_8233A, "VIA 8233A", TYPE_VIA8233A },
        { VIA_REV_8235, "VIA 8235", TYPE_VIA8233 },
+       { VIA_REV_8237, "VIA 8237", TYPE_VIA8233 },
 };
 
 /*
@@ -2095,15 +2107,19 @@ static int __devinit check_dxs_list(struct pci_dev *pci)
                { .vendor = 0x1071, .device = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */
                { .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */
                { .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */
+               { .vendor = 0x1106, .device = 0x4552, .action = VIA_DXS_NO_VRA }, /* QDI Kudoz 7X/600-6AL */
                { .vendor = 0x1106, .device = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */
                { .vendor = 0x1297, .device = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */
                { .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */
-               { .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_NO_VRA }, /* Gigabyte GA-7VAXP (FIXME: or DXS_ENABLE?) */
-               { .vendor = 0x147b, .device = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
-               { .vendor = 0x14ff, .device = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */
+               { .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */
                { .vendor = 0x1462, .device = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
-               { .vendor = 0x1462, .device = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
                { .vendor = 0x1462, .device = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
+               { .vendor = 0x1462, .device = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
+               { .vendor = 0x147b, .device = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
+               { .vendor = 0x147b, .device = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */
+               { .vendor = 0x147b, .device = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */
+               { .vendor = 0x147b, .device = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */
+               { .vendor = 0x14ff, .device = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */
                { .vendor = 0x1584, .device = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */
                { .vendor = 0x1584, .device = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */
                { .vendor = 0x161f, .device = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */
@@ -2194,6 +2210,8 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
                }
                if (chip_type == TYPE_VIA8233A)
                        strcpy(card->driver, "VIA8233A");
+               else if (revision >= VIA_REV_8237)
+                       strcpy(card->driver, "VIA8237"); /* no slog assignment */
                else
                        strcpy(card->driver, "VIA8233");
                break;
@@ -2235,8 +2253,9 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
        for (i = 0; i < chip->num_devs; i++)
                snd_via82xx_channel_reset(chip, &chip->devs[i]);
 
-       sprintf(card->longname, "%s at 0x%lx, irq %d",
-               card->shortname, chip->port, chip->irq);
+       snprintf(card->longname, sizeof(card->longname),
+                "%s with %s at %#lx, irq %d", card->shortname,
+                snd_ac97_get_short_name(chip->ac97), chip->port, chip->irq);
 
        snd_via82xx_proc_init(chip);