From mboxrd@z Thu Jan 1 00:00:00 1970 From: Takashi Iwai Subject: Re: VIA823x testing Date: Tue, 28 Jan 2003 17:21:10 +0100 Sender: alsa-devel-admin@lists.sourceforge.net Message-ID: References: <200301221234.33054.tais.hansen@osd.dk> <200301280143.40285.tais.hansen@osd.dk> <200301281425.38097.tais.hansen@osd.dk> Mime-Version: 1.0 (generated by SEMI 1.14.4 - "Hosorogi") Content-Type: multipart/mixed; boundary="Multipart_Tue_Jan_28_17:21:10_2003-1" Return-path: In-Reply-To: <200301281425.38097.tais.hansen@osd.dk> Errors-To: alsa-devel-admin@lists.sourceforge.net List-Help: List-Post: List-Subscribe: , List-Unsubscribe: , List-Archive: To: "Tais M. Hansen" Cc: alsa-devel@lists.sourceforge.net List-Id: alsa-devel@alsa-project.org --Multipart_Tue_Jan_28_17:21:10_2003-1 Content-Type: text/plain; charset=US-ASCII At Tue, 28 Jan 2003 14:25:31 +0100, Tais M. Hansen wrote: > > On Tuesday 28 January 2003 10:31, Takashi Iwai wrote: > > > > how about this one? > > > Still no sound. More logs for you to digest. > > please check the mixer configuration. > > there must be any sounds, even though pops/clicks and error messages > > might come. > > No sound at all. I've tried turning everything up to full volume, unmuting > everything, tried all three onboard minijacks. Not a peep. hmm, then it seems something goes wrong completely. at least, i see the "invalid CURR_PTR" error at each call. it's weird. did you see this in the log of ogg123? > - From what I can see when playing with ogg123, it's speeding through the > ogg-file. It took 4.8s to play 10s ogg-file. interesting. the new patch will put the timestamp at each interrupt, so you can measure the period time between interrupts. this shoud be (period-size-in-frames * 4 / sample-rate) please compare the measured values. > Btw while testing I got 23MB logoutput, want it? ;) no, it would be filtered as a spam, anyway :) ciao, Takashi --Multipart_Tue_Jan_28_17:21:10_2003-1 Content-Type: application/octet-stream Content-Disposition: attachment; filename="via-pointer-test12.dif" Content-Transfer-Encoding: 7bit Index: alsa-kernel/pci/via82xx.c =================================================================== RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/pci/via82xx.c,v retrieving revision 1.21 diff -u -r1.21 via82xx.c --- alsa-kernel/pci/via82xx.c 22 Jan 2003 14:21:05 -0000 1.21 +++ alsa-kernel/pci/via82xx.c 28 Jan 2003 16:15:07 -0000 @@ -88,7 +88,7 @@ MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); MODULE_PARM_DESC(mpu_port, "MPU-401 port."); MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT_DESC); -MODULE_PARM(ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); +MODULE_PARM(ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:48000"); @@ -230,10 +230,13 @@ u32 *table; /* physical address + flag */ dma_addr_t table_addr; struct snd_via_sg_table *idx_table; + int *period_idx; + unsigned int periods; /* for recovery from the unexpected pointer */ + unsigned int intr_cnt; unsigned int lastpos; + unsigned int lastidx; unsigned int bufsize; - unsigned int bufsize2; }; @@ -262,11 +265,17 @@ if (! dev->idx_table) return -ENOMEM; } + if (! dev->period_idx) { + dev->period_idx = kmalloc(sizeof(int) * VIA_TABLE_SIZE, GFP_KERNEL); + if (! dev->period_idx) + return -ENOMEM; + } /* fill the entries */ idx = 0; ofs = 0; for (i = 0; i < periods; i++) { + dev->period_idx[i] = idx; rest = fragsize; /* fill descriptors for a period. * a period can be split to several descriptors if it's @@ -302,7 +311,7 @@ } dev->tbl_entries = idx; dev->bufsize = periods * fragsize; - dev->bufsize2 = dev->bufsize / 2; + dev->periods = periods; return 0; } @@ -318,13 +327,18 @@ kfree(dev->idx_table); dev->idx_table = NULL; } + if (dev->period_idx) { + kfree(dev->period_idx); + dev->period_idx = NULL; + } } /* */ -enum { TYPE_VIA686 = 1, TYPE_VIA8233 }; +enum { TYPE_CARD_VIA686 = 1, TYPE_CARD_VIA8233 }; +enum { TYPE_VIA686, TYPE_VIA8233, TYPE_VIA8233A }; #define VIA_MAX_DEVS 7 /* 4 playback, 1 multi, 2 capture */ @@ -365,8 +379,8 @@ }; static struct pci_device_id snd_via82xx_ids[] __devinitdata = { - { 0x1106, 0x3058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_VIA686, }, /* 686A */ - { 0x1106, 0x3059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_VIA8233, }, /* VT8233 */ + { 0x1106, 0x3058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA686, }, /* 686A */ + { 0x1106, 0x3059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA8233, }, /* VT8233 */ { 0, } }; @@ -485,6 +499,8 @@ outb(0x00, port + VIA_REG_OFFSET_TYPE); /* for via686 */ outl(0, port + VIA_REG_OFFSET_CURR_PTR); viadev->lastpos = 0; + viadev->lastidx = 0; + viadev->intr_cnt = 0; } @@ -512,13 +528,26 @@ /* check status for each stream */ for (i = 0; i < chip->num_devs; i++) { viadev_t *viadev = &chip->devs[i]; - if (inb(chip->port + viadev->reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG)) { - outb(VIA_REG_STAT_FLAG | VIA_REG_STAT_EOL, VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset); - if (viadev->substream && viadev->running) { - spin_unlock(&chip->reg_lock); - snd_pcm_period_elapsed(viadev->substream); - spin_lock(&chip->reg_lock); + unsigned long port = chip->port + viadev->reg_offset; /* STATUS */ + unsigned char status = inb(port); + status &= (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG); + if (! status) + continue; + outb(status, port); /* ack */ + if (viadev->substream && viadev->running) { + viadev->intr_cnt++; + if (viadev->intr_cnt >= viadev->periods) + viadev->intr_cnt = 0; + spin_unlock(&chip->reg_lock); +#ifdef POINTER_DEBUG + { + struct timeval tval; + do_gettimeofday(&tval); + snd_printd("period elapsed: %d.%06d\n", tv->sec, tv->usec); } +#endif + snd_pcm_period_elapsed(viadev->substream); + spin_lock(&chip->reg_lock); } } spin_unlock(&chip->reg_lock); @@ -538,7 +567,7 @@ unsigned char val; unsigned long port = chip->port + viadev->reg_offset; - if (chip->chip_type == TYPE_VIA8233) + if (chip->chip_type != TYPE_VIA686) val = VIA_REG_CTRL_INT; else val = 0; @@ -573,35 +602,87 @@ */ /* + * check whether the given index is within the current area + */ +static inline int out_of_intr_idx(viadev_t *viadev, unsigned int idx) +{ + unsigned int cnt; + + if (idx < viadev->period_idx[viadev->intr_cnt]) + return 1; + cnt = viadev->intr_cnt + 1; + if (cnt != viadev->periods && idx >= viadev->period_idx[cnt]) + return 1; + return 0; +} + +/* * calculate the linear position at the given sg-buffer index and the rest count */ -static inline unsigned int calc_linear_pos(viadev_t *viadev, unsigned int idx, unsigned int count) +static unsigned int calc_linear_pos(viadev_t *viadev, unsigned int idx, unsigned int count, int recover) { - unsigned int size, res; + unsigned int size, res = 0; - size = viadev->idx_table[idx].size; - res = viadev->idx_table[idx].offset + size - count; + if (recover > 0) + goto _check; - /* check the validity of the calculated position */ - if (size < count || (res < viadev->lastpos && (res >= viadev->bufsize2 || viadev->lastpos < viadev->bufsize2))) { + size = viadev->idx_table[idx].size; #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); + snd_printd("calc_linear_pos: idx = %i/%i, lastpos = 0x%x, size = 0x%x, count = 0x%x\n", idx, viadev->tbl_entries, viadev->lastpos, size, count); #endif - /* count register returns full size when end of buffer is reached */ - if (size != count) { - snd_printd(KERN_ERR "invalid via82xx_cur_ptr, using last valid pointer\n"); - res = viadev->lastpos; - } else { - res = viadev->idx_table[idx].offset + size; - if (res < viadev->lastpos && (res >= viadev->bufsize2 || viadev->lastpos < viadev->bufsize2)) { - snd_printd(KERN_ERR "invalid via82xx_cur_ptr (2), using last valid pointer\n"); - res = viadev->lastpos; + if (count == 0) { + /* fully processed, increase the index */ + if (++idx >= viadev->tbl_entries) + idx = 0; + res = viadev->idx_table[idx].offset; + } else if (count > size) { + /* totally corrupted? get the position from interrupt ptr */ + recover = 2; + goto _check; + } else { + res = viadev->idx_table[idx].offset + size - count; + } + + if (out_of_intr_idx(viadev, idx)) { + if (size == count) { + /* count register returns full size when end of buffer is reached */ + if (++idx >= viadev->tbl_entries) + idx = 0; + if (! out_of_intr_idx(viadev, idx)) { + res = viadev->idx_table[idx].offset; + goto _ok; } } + recover = 2; + } else if (res < viadev->lastpos) + recover = 1; + + _check: + if (recover > 0) { + if (! out_of_intr_idx(viadev, viadev->lastidx)) { +#ifdef POINTER_DEBUG + snd_printd("recover from last\n"); +#endif + return viadev->lastpos; + } + if (recover > 1) { + /* recover from the interrupt pointer */ + idx = viadev->period_idx[viadev->intr_cnt]; + res = viadev->idx_table[idx].offset; +#ifdef POINTER_DEBUG + snd_printd("recover from intr: idx = %i, ptr = 0x%x\n", idx, res); +#endif + } } - viadev->lastpos = res; /* remember the last positiion */ + + _ok: if (res >= viadev->bufsize) res -= viadev->bufsize; + viadev->lastidx = idx; + viadev->lastpos = res; +#ifdef POINTER_DEBUG + snd_printd("get position: 0x%x, idx = %d\n", res, idx); +#endif return res; } @@ -628,7 +709,7 @@ idx = 0; else /* CURR_PTR holds the address + 8 */ idx = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries; - res = calc_linear_pos(viadev, idx, count); + res = calc_linear_pos(viadev, idx, count, 0); spin_unlock(&chip->reg_lock); return bytes_to_frames(substream->runtime, res); @@ -642,15 +723,27 @@ via82xx_t *chip = snd_pcm_substream_chip(substream); viadev_t *viadev = (viadev_t *)substream->runtime->private_data; unsigned int idx, count, res; + int timeout, recover; snd_assert(viadev->tbl_entries, return 0); if (!(inb(VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset) & VIA_REG_STAT_ACTIVE)) return 0; + recover = 0; + timeout = 50; + do { + count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset); + if (count != (unsigned int)-1) + goto _got_count; + } while (timeout-- > 0); +#ifdef POINTER_DEBUG + snd_printd("invalid CURR_COUNT reg\n"); +#endif + recover = 2; + _got_count: spin_lock(&chip->reg_lock); - count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset); - idx = count >> 24; + idx = (count >> 24) & viadev->tbl_entries; count &= 0xffffff; - res = calc_linear_pos(viadev, idx, count); + res = calc_linear_pos(viadev, idx, count, recover); spin_unlock(&chip->reg_lock); return bytes_to_frames(substream->runtime, res); @@ -696,6 +789,17 @@ /* + * set up the table pointer + */ +static void snd_via82xx_set_table_ptr(via82xx_t *chip, viadev_t *viadev) +{ + snd_via82xx_codec_ready(chip, 0); + outl((u32)viadev->table_addr, VIAREG(chip, OFFSET_TABLE_PTR) + viadev->reg_offset); + udelay(20); + snd_via82xx_codec_ready(chip, 0); +} + +/* * prepare callback for playback and capture on via686 */ static void via686_setup_format(via82xx_t *chip, viadev_t *viadev, snd_pcm_runtime_t *runtime) @@ -704,7 +808,7 @@ snd_via82xx_channel_reset(chip, viadev); /* this must be set after channel_reset */ - outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR); + snd_via82xx_set_table_ptr(chip, viadev); outb(VIA_REG_TYPE_AUTOSTART | (runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA_REG_TYPE_16BIT : 0) | (runtime->channels > 1 ? VIA_REG_TYPE_STEREO : 0) | @@ -777,7 +881,7 @@ rbits = (0xfffff / 48000) * runtime->rate + ((0xfffff % 48000) * runtime->rate) / 48000; snd_assert((rbits & ~0xfffff) == 0, return -EINVAL); snd_via82xx_channel_reset(chip, viadev); - outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR); + snd_via82xx_set_table_ptr(chip, viadev); outb(0 , VIAREG(chip, PLAYBACK_VOLUME_L)); outb(0 , VIAREG(chip, PLAYBACK_VOLUME_R)); outl((runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA8233_REG_TYPE_16BIT : 0) | /* format */ @@ -785,6 +889,8 @@ rbits | /* rate */ 0xff000000, /* STOP index is never reached */ port + VIA_REG_OFFSET_STOP_IDX); + udelay(20); + snd_via82xx_codec_ready(chip, 0); return 0; } @@ -807,7 +913,7 @@ snd_ac97_set_rate(chip->ac97, AC97_PCM_LFE_DAC_RATE, runtime->rate); snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate); snd_via82xx_channel_reset(chip, viadev); - outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR); + snd_via82xx_set_table_ptr(chip, viadev); fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT; fmt |= runtime->channels << 4; @@ -825,6 +931,8 @@ } /* STOP index is never reached */ outl(0xff000000 | slots, port + VIA_REG_OFFSET_STOP_IDX); + udelay(20); + snd_via82xx_codec_ready(chip, 0); return 0; } @@ -842,7 +950,7 @@ return -EINVAL; snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); snd_via82xx_channel_reset(chip, viadev); - outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR); + snd_via82xx_set_table_ptr(chip, viadev); outb(VIA_REG_CAPTURE_FIFO_ENABLE, VIAREG(chip, CAPTURE_FIFO)); outl((runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA8233_REG_TYPE_16BIT : 0) | (runtime->channels > 1 ? VIA8233_REG_TYPE_STEREO : 0) | @@ -950,7 +1058,7 @@ if ((err = snd_via82xx_pcm_open(chip, viadev, substream)) < 0) return err; substream->runtime->hw.channels_max = 6; - if (chip->revision == VIA_REV_8233A) + if (chip->chip_type == TYPE_VIA8233A) snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels); return 0; } @@ -1306,6 +1414,12 @@ ac97.clock = chip->ac97_clock; if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0) return err; + + if (chip->chip_type != TYPE_VIA686) { + /* use slot 10/11 */ + snd_ac97_update_bits(chip->ac97, AC97_EXTENDED_STATUS, 0x03 << 4, 0x03 << 4); + } + return 0; } @@ -1365,7 +1479,7 @@ int i, err, caps; unsigned char val; - caps = chip->revision == VIA_REV_8233A ? 1 : 2; + caps = chip->chip_type == TYPE_VIA8233A ? 1 : 2; for (i = 0; i < caps; i++) { snd_via8233_capture_source.index = i; err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_capture_source, chip)); @@ -1651,6 +1765,19 @@ return 0; } +struct via823x_info { + int revision; + char *name; + int type; +}; +static struct via823x_info via823x_cards[] __devinitdata = { + { VIA_REV_PRE_8233, "VIA 8233-Pre", TYPE_VIA8233 }, + { VIA_REV_8233C, "VIA 8233C", TYPE_VIA8233 }, + { VIA_REV_8233, "VIA 8233", TYPE_VIA8233 }, + { VIA_REV_8233A, "VIA 8233A", TYPE_VIA8233A }, + { VIA_REV_8233, "VIA 8235", TYPE_VIA8233 }, +}; + static int __devinit snd_via82xx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -1658,7 +1785,7 @@ snd_card_t *card; via82xx_t *chip; unsigned char revision; - int chip_type; + int chip_type = 0, card_type; int i, err; if (dev >= SNDRV_CARDS) @@ -1672,24 +1799,31 @@ if (card == NULL) return -ENOMEM; - chip_type = pci_id->driver_data; + card_type = pci_id->driver_data; pci_read_config_byte(pci, PCI_REVISION_ID, &revision); - switch (chip_type) { - case TYPE_VIA686: + switch (card_type) { + case TYPE_CARD_VIA686: strcpy(card->driver, "VIA686A"); strcpy(card->shortname, "VIA 82C686A/B"); + chip_type = TYPE_VIA686; break; - case TYPE_VIA8233: - if (revision == VIA_REV_8233A) { + case TYPE_CARD_VIA8233: + chip_type = TYPE_VIA8233; + sprintf(card->shortname, "VIA 823x rev%d", revision); + for (i = 0; i < ARRAY_SIZE(via823x_cards); i++) { + if (revision == via823x_cards[i].revision) { + chip_type = via823x_cards[i].type; + strcpy(card->shortname, via823x_cards[i].name); + break; + } + } + if (chip_type == VIA_REV_8233A) strcpy(card->driver, "VIA8233A"); - strcpy(card->shortname, "VIA 8233A"); - } else { + else strcpy(card->driver, "VIA8233"); - strcpy(card->shortname, "VIA 8233/C"); - } break; default: - snd_printk(KERN_ERR "invalid chip type %d\n", chip_type); + snd_printk(KERN_ERR "invalid card type %d\n", card_type); err = -EINVAL; goto __error; } @@ -1705,7 +1839,7 @@ (err = snd_via686_init_misc(chip, dev)) < 0) goto __error; } else { - if (revision == VIA_REV_8233A) { + if (chip_type == VIA_REV_8233A) { if ((err = snd_via8233a_pcm_new(chip)) < 0) goto __error; } else { @@ -1792,4 +1926,3 @@ __setup("snd-via82xx=", alsa_card_via82xx_setup); #endif /* ifndef MODULE */ - --Multipart_Tue_Jan_28_17:21:10_2003-1-- ------------------------------------------------------- This SF.NET email is sponsored by: SourceForge Enterprise Edition + IBM + LinuxWorld = Something 2 See! http://www.vasoftware.com