X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sound%2Fpci%2Fvia82xx.c;h=5b26b52d55e57490827d3ee77db5598f92d66534;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=fb549ea9eec9e156c69b25d88ff071c003420525;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index fb549ea9e..5b26b52d5 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -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);